A31-期中考试(部分)

call、apply、bind

相同的地方

  1. 三者都是用来改变函数体内 this 对象的值
  2. 第一个参数都是 this 要指向的对象
  3. 可以接受更多参数(即第二个开始)来对函数传参
    不同的地方
  4. call 与 apply
    两者的却别仅在于接受后续参数方式的不同
    call第一个参数是this值没有变化,其余参数都是直接传递,也就是全部列举出来

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    function sum(x,y){
    if(x&&y){
    return (this.a + this.b + x + y)
    } else{
    return (this.a + this.b)
    }
    }
    var obj1 = {
    a: 1,
    b: 2
    }
    var obj2 = {
    c: 3,
    d: 4
    }
    console.log(sum.call(obj1)) // 3
    console.log(sum.call(obj1, obj2.c, obj2.d)) // 10

    apply的第一个参数为this值,第二个参数可以是 Array 的实例,也可以使 arguments 对象,也就是伪数组

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    function sum(x,y){
    if(x&&y){
    return (this.a + this.b + x + y)
    } else{
    return (this.a + this.b)
    }
    }
    var obj1 = {
    a: 1,
    b: 2
    }
    var obj3 = { // 伪数组
    0: 3,
    1: 4,
    length:2
    }
    console.log(sum.apply(obj1)) // 3
    console.log(sum.apply(obj1, obj3)) // 10
    console.log(sum.apply(obj1, [3,4])) // 10 传入数组
    // 传入 arguments 对象
    function sumall(a,b){
    this.a = 1
    this.b = 2
    return sum.apply(this, arguments)
    }
    console.log(sumall(3,4))
  5. bind 与前两者不同的返回值
    函数.call() 和 函数.apply() 都是对函数的直接调用
    而bind不同,它返回指定了this值的函数
    它也可以像call那样传参

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    function sum(x,y){
    if(x&&y){
    return (this.a + this.b + x + y)
    } else{
    return (this.a + this.b)
    }
    }
    var obj1 = {
    a: 1,
    b: 2
    }
    var obj2 = {
    c: 3,
    d: 4
    }
    var sum2 = sum.bind(obj1)
    console.log(sum2()) // 3
    console.log(sum2(obj2.c, obj2.d)) // 10

    CSS-移动端页面(响应式)

媒体查询

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 样式表中的CSS媒体查询
<style>
@media (min-width: 769px){
body{ background-color: purple;}
}
@media (min-width: 321px) and (max-width: 768px){
body{ background-color: orange;}
}
@media (max-width: 320px){
body{ background-color: red;}
}
</style>
// link元素中的CSS媒体查询
<link rel="stylesheet" media="(max-width: 800px)" href="example.css" />

动态 REM

rem

  1. 这个单位代表根元素的 font-size 大小(例如 元素的font-size)。
  2. rem 与 em 的区别
    首先理解em的意义,它表示当前元素的font-size的计算值,即em==font-size
    两者区别:rem 是相对于根元素的 font-size,而 em 是相对于当前元素的font-size
  3. 手机端方案的特点
    • 所有手机显示的界面都是一样的,只是大小不同
    • 1 rem == html font-size == viewport width

      一切单位以宽度为基准,就能完美还原设计稿
  4. 使用 js 动态调整 rem

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    // html
    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="utf-8">
    <title>JS Bin</title>
    <script>
    // 1 rem 等于一个页面的宽度
    var pageWidth = window.innerWidth
    document.write('<style>html{font-size: '+pageWidth+'px;}</style>')
    </script>
    </head>
    <body>
    <div class="parent clearfix">
    <div class="child">1</div>
    <div class="child">2</div>
    <div class="child">3</div>
    <div class="child">4</div>
    </div>
    </body>
    </html>
    // css
    *{margin:0;padding:0;}
    body{
    // 设置字体大小,不然就变成和页面一样大了
    font-size: 16px;
    }
    .child{
    background-color: #ddd;
    float: left;
    }
    .clearfix::after{
    content: '';
    display: block;
    clear: both;
    }
    // 所有宽高边距等都用 rem 设置
    .child{
    width: 0.4rem;
    height: 0.2rem;
    margin: 0.05rem;
    }

    这样,不论手机宽度如何,比例仍然是一样的,只是大小不同
    另外,直接将rem与页面宽度等同,太大了,设置css都要使用小数,很麻烦
    所以可以设置的小一点,比如百分之一,但是这样可能会出现一个新的问题

    1
    2
    var pageWidth = window.innerWidth
    document.write('<style>html{font-size: '+ pageWidth/100 +'px;}</style>')

    得到的font-size值太小,别忘了chrome默认限制font-size最小为12px,于是页面就变‘大了’
    为了防止这样的情况,不能除以太大的数字

    1
    2
    var pageWidth = window.innerWidth
    document.write('<style>html{font-size: '+ pageWidth/10 +'px;}</style>')

    一般而言,10比较合适,因为智能手机屏幕通常在300-400px左右,除以10后在30-40,不会出现因为‘12px原则’而被‘放大页面’

  5. rem 可以与其他单位同时存在

    1
    2
    3
    font-size: 16px;
    border: 1px solid red;
    width: 0.5rem;

    比如 font-size,如果使用rem,会在屏幕很小的时候变得很难看
    还有border,1px转换rem在屏幕太小的时候仍然是1px,因为浏览器最小就是1px了
    这里建议太小的单位,或者如font-size这样的(字体太大太小都不好看),可以使用其它单位与rem混合使用
    比如px、em

  6. 在 SCSS 里使用 PX2REM
    这个是node-sass,
    npm config set registry https://registry.npm.taobao.org/
    touch ~/.bashrc
    echo ‘export SASS_BINARY_SITE=”https://npm.taobao.org/mirrors/node-sass“‘ >> ~/.bashrc
    source ~/.bashrc
    npm i -g node-sass
    mkdir ~/Desktop/scss-demo
    cd ~/Desktop/scss-demo
    mkdir scss css
    touch scss/style.scss
    start scss/style.scss
    node-sass -wr scss -o css

    编辑 scss 文件就会自动得到 css 文件

    在 scss 文件里添加

    @function px( $px ){
    @return $px/$designWidth*10 + rem;
    }

    $designWidth : 640; // 640 是设计稿的宽度,你要根据设计稿的宽度填写。如果设计师的设计稿宽度不统一,就杀死设计师,换个新的。

    .child{
    width: px(320);
    height: px(160);
    margin: px(40) px(40);
    border: 1px solid red;
    float: left;
    font-size: 1.2em;
    }
    即可实现 px 自动变 rem
    饥人谷教学视频

一些知识点

  • 如果不给页面添加font-size,则默认字体大小为16px
  • Chrome有最小字号设置,一般默认为12px,这个时候即使你设置更小的像素也无法生效,依然是12px(仅chrome)

闭包

  1. 什么是闭包
    闭包就是 函数和函数访问的函数外部变量的总和,
    1
    2
    3
    4
    var num = 100
    function addNum(){
    num += 1
    }

在上面,变量num+函数addNum就是闭包
实际上我们经常在用的东西

  1. 为什么要用闭包
    有时候我们需要隐藏变量,而不是直接访问他,来避免外部污染,
    通过函数来模拟块,在函数内部建立一个子函数来访问隐藏的变量,
    return这个子函数给外部的变量进行调用,来对隐藏变量进行操作,
    也因此,隐藏变量无法被垃圾回收销毁,在ie中会因为bug而出现内存泄漏
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    function test(){
    var num = 1
    return function setNum(n){
    num = n
    return num
    }
    }
    var sn = test()
    console.log( sn(1) )
    console.log( sn(2) )
    console.log( sn(3) )

请说出至少三种排序的思路,这三种排序的时间复杂度分别为

O(n*n)
O(n log2 n)
O(n + max)

  1. O(n*n)
    冒泡排序:比较相邻的元素,如果第一个比第二个大,就交换他们两个,对每一对相邻的元素做同样的工作,从开始第一对到结尾最后一对,这步会让后一位元素就是最大的数,对所有元素重复以上步骤,除了最后一个,直到没有任何一堆数字需要比较
  2. O(n log2 n)
    快速排序:以一个元素为基准,重新排序数列,比基准值小的元素放左边,大的放右边,然后在对左半边和右半边重复以上操作,直到只有一个数字为止
  3. O(n + max)
    基数排序:将所有待比较数值(正整数)统一为同样的数位长度,数位较短的数前面补零。然后,从最低位开始,依次进行一次排序。这样从最低位排序一直到最高位排序完成以后,数列就变成一个有序序列。

著名前端面试题:

一个页面从输入 URL 到页面加载显示完成,这个过程中都发生了什么?

  1. DNS解析

    DNS解析的过程就是寻找哪台机器上有你需要资源的过程。当你在浏览器地址栏输入一个地址比如:www.baidu.com,其实并不是百度真正的地址,这只是方便人们记忆和理解所设计的,真正的地址是IP地址,而www.baidu.com是域名(ip地址和域名并不是一一对应的),DNS解析就是将你输入的域名解析成ip地址。

    查找(解析)过程:搜索浏览器自己的DNS缓存 –> 搜索操作系统中的DNS缓存 –> 搜索操作系统的hosts文件 –> 发送域名到本地域名服务器查询 –> 向根域名服务器查询 –> 向顶级域名服务器查询,

    得到ip地址,返回给浏览器,同时浏览器将ip地址缓存
  2. TCP连接
    得到服务器的ip地址后,接下来开始连接,总的来说需要经历以下三个过程(简称三次握手):
    1. 主机想服务器发送一个建立连接的请求(您好,我想认识您);
    2. 服务器接到请求后发送同意连接的信号(好的,很高兴认识您);
    3. 主机接到同意连接的信号后,再次向服务器发送了确认信号(我也很高兴认识您),自此,主机与服务器建立了连接
  3. 发送HTTP请求
    浏览器根据URL内容生成HTTP请求,HTTP报文被包裹在TCP报文中发送 ,服务器收到TCP报文是会解包提取出HTTP报文,它主要由三部分组成
    1. 请求行:请求方法 资源路径 HTTP协议版本
    2. 请求报头:请求报头允许客户端向服务器传递请求的附加信息和客户端自身的信息。
    3. 请求正文
  4. 服务器处理请求并返回HTTP报文
    HTTP响应报文也是由三部分组成: 状态码, 响应报头和响应报文。
  5. 浏览器解析渲染页面
    浏览器是一个边解析边渲染的过程。首先浏览器解析HTML文件构建DOM树,然后解析CSS文件构建渲染树,等到渲染树构建完成后,浏览器开始布局渲染树并将其绘制到屏幕上。
  6. 连接结束
    1. 主机向服务器发送一个断开连接的请求(不早了,我该走了);
    2. 服务器接到请求后发送确认收到请求的信号(知道了);
    3. 服务器向主机发送断开通知(我也该走了);
    4. 主机接到断开通知后断开连接并反馈一个确认信号(嗯,好的),服务器收到确认信号后断开连接;

如何实现数组去重?

假设有数组 array = [1,5,2,3,4,2,3,1,3,4]
你要写一个函数 unique,使得
unique(array) 的值为 [1,5,2,3,4]
也就是把重复的值都去掉,只保留不重复的值。

要求:

不要做多重循环,只能遍历一次
请给出两种方案,一种能在 ES 5 环境中运行,一种能在 ES 6 环境中运行(提示 ES 6 环境多了一个 Set 对象)

答案:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//  ES5:
var array = [1,5,2,3,4,2,3,1,3,4]
function unique(arr){
var tempArr = []
var hash = {}
for(var i=0; i<arr.length; i++){
if(hash[arr[i]] === undefined){
tempArr.push(arr[i])
hash[arr[i]] = 1
}
}
return tempArr
}
console.log(unique(array))

// ES6:
var arr = [1,5,2,3,4,2,3,1,3,4]
function unique(array) {
return [...new Set(array)]
}
console.log(unique(arr))