# 前端面试题及答案汇总(四) 41-50

# 第 41 题:下面代码输出什么

var a = 10;
(function () {
    console.log(a)
    a = 5
    console.log(window.a)
    var a = 20;
    console.log(a)
})()
1
2
3
4
5
6
7
8
  • undefined
  • 10
  • 20

# 第 42 题:实现一个 sleep 函数

promise

function sleep(time) {
    return new Promise((resolve, reject) => {
        setTimeout(resolve, time);
    })
}
sleep(1000).then(() => console.log(1));
1
2
3
4
5
6

async

function sleep(time) {
    return new Promise(resolve => setTimeout(resolve, time))
}

async function sleepAsync(time) {
    console.log(1111);
    await sleep(time);
    console.log(222);
}
1
2
3
4
5
6
7
8
9

Generator

function *sleep(time) {
    yield new Promise((resolve) => {
        setTimeout(resolve, time);
    })
}
sleep(1000).next()
1
2
3
4
5
6

es5

function sleep(callback, time) {
    if (typeof callback === 'function') {
        setTimeout(callback, time);
    }
}

function output() {
    console.log(111);
}

sleep(output, 1000);
1
2
3
4
5
6
7
8
9
10
11

# 第 43 题:使用 sort() 对数组 [3, 15, 8, 29, 102, 22] 进行排序,输出结果

102 15 22 29 3 8

默认的排序方法会将数组元素转换为字符串,然后比较字符串中字符的UTF-16编码顺序来进行排序。

# 第 44 题:介绍 HTTPS 握手过程

  1. 浏览器 发送随机数 random1 + 支持的加密算法列表 到服务器
  2. 服务器 发送随机数 random2 + 选择的加密算法 + 数字证书(公钥在证书里) + 确认信息
  3. 浏览器 验证证书有效性
  4. 浏览器 生成一个随机数 pre-master,采用非对称加密通过服务器的公钥加密发送给服务器,同时根据加密算法将 random1 + random2 + pre-master 生成 master-secret 用于后续数据传输
  5. 服务器 用私钥解密得到 pre-master,根据算法将 random1 + random2 + pre-master 生成 master-secret用于数据传输
  6. 对称加密,浏览器和服务器之间使用 master-secret 加密的数据进行通信

# 第 45 题:HTTPS 握手过程中,客户端如何验证证书的合法性

  1. 首先浏览器读取证书中的证书所有者、有效期等信息进行校验,校验证书的网站域名是否与证书颁发的域名一致,校验证书是否在有效期内
  2. 浏览器开始查找操作系统中已内置的受信任的证书发布机构CA,与服务器发来的证书中的颁发者CA比对,用于校验证书是否为合法机构颁发,但是这个 CA 可能比较小众,浏览器不知道该不该信任它,然后浏览器会继续查找给这个 CA 颁发证书的 CA,再以同样的方式验证它上级 CA 的可靠性。
  3. 如果找不到,浏览器就会报错,说明服务器发来的证书是不可信任的。
  4. 如果找到,那么浏览器就会从操作系统中取出颁发者CA 的公钥(多数浏览器开发商发布版本时,会事先在内部植入常用认证机关的公开密钥),然后对服务器发来的证书里面的签名进行解密
  5. 浏览器使用相同的hash算法计算出服务器发来的证书的hash值,将这个计算的hash值与证书中签名做对比
  6. 对比结果一致,则证明服务器发来的证书合法,没有被冒充

# 第 46 题:输出以下代码执行的结果并解释为什么

var obj = {
    '2': 3,
    '3': 4,
    'length': 2,
    'splice': Array.prototype.splice,
    'push': Array.prototype.push
}
obj.push(1)
obj.push(2)
console.log(obj)

// [empty × 2, 1, 2, splice: ƒ, push: ƒ]
1
2
3
4
5
6
7
8
9
10
11
12

类数组:

  • 对象上有splice,且splice是一个函数;
  • 对象上含有length属性,且是个数字;

满足上面两个要求就是类数组

push 方法根据 length 属性来决定从哪里开始插入给定的值。 push 是特意设计为通用的,Array.prototype.push 可以在一个对象上工作。

  • 满足要求所以输出是个类数组
  • push是从length开始的,所以从2开始,即类数组的前两位是空,所以自动补上empty
  • obj.push(1) -> obj[2] = 1
  • obj.push(2) -> obj[3] = 2
  • 输出 [empty × 2, 1, 2, splice: ƒ, push: ƒ]

# 第 47 题:双向绑定和 vuex 是否冲突

# 第 48 题:call 和 apply 的区别是什么,哪个性能更好一些

  1. Function.prototype.apply和Function.prototype.call 的作用是一样的,区别在于传入参数的不同;
  2. 第一个参数都是,指定函数体内this的指向;
  3. 第二个参数开始不同,apply是传入带下标的集合,数组或者类数组,apply把它传给函数作为参数,call从第二个开始传入的参数是不固定的,都会传给函数作为参数。
  4. call比apply的性能要好,平常可以多用call, call传入参数的格式正是内部所需要的格式,参考call和apply性能对比

# 第 49 题:为什么通常在发送数据埋点请求的时候使用的是 1x1 像素的透明 gif 图片?

  1. 能够完成整个 HTTP 请求+响应(尽管不需要响应内容)
  2. 触发 GET 请求之后不需要获取和处理数据、服务器也不需要发送数据
  3. 跨域友好
  4. 执行过程无阻塞
  5. 相比 XMLHttpRequest 对象发送 GET 请求,性能上更好
  6. GIF的最低合法体积最小(最小的BMP文件需要74个字节,PNG需要67个字节,而合法的GIF,只需要43个字节)

# 第 50 题:(百度)实现 (5).add(3).minus(2) 功能。

Number.prototype.add = function(n) {
    if (typeof n !== 'number') {
        throw new Error('请输入数字');
    }
    return this + n;
}

Number.prototype.minus = function(n) {
    if (typeof n !== 'number') {
        throw new Error('请输入数字');
    }
    return this - n;
}

console.log((5).add(3).minus(2))
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15