# 前端面试题及答案汇总(九) 91-100

# 第 91 题:介绍下 HTTPS 中间人攻击

https 协议由 http + ssl 协议构成,具体的链接过程可参考 SSL 或 TLS 握手的概述

中间人攻击过程如下:

  • 服务器向客户端发送公钥。
  • 攻击者截获公钥,保留在自己手上。
  • 然后攻击者自己生成一个【伪造的】公钥,发给客户端。
  • 客户端收到伪造的公钥后,生成加密 hash 值发给服务器。
  • 攻击者获得加密 hash 值,用自己的私钥解密获得真秘钥。
  • 同时生成假的加密 hash 值,发给服务器。
  • 服务器用私钥解密获得假秘钥。 -服务器用加秘钥加密传输信息

防范方法:

服务端在发送浏览器的公钥中加入 CA 证书,浏览器可以验证 CA 证书的有效性

# 第 92 题:已知数据格式,实现一个函数 fn 找出链条中所有的父级 id

let list = [
  {
    id: "1",
    children: [
      {
        id: "11",
        children: [
          {
            id: "111"
          },
          {
            id: "112"
          }
        ]
      }
    ]
  }
];

function fn(value) {
  // 回溯的标记
  let _p = Symbol("parent");
  // 找到子节点
  let result;
  function _fn(arr, p) {
    for (let i = 0; i < arr.length; i++) {
      arr[i][_p] = p;
      if (arr[i].id === value) {
        result = arr[i];
        return;
      }
      !result && arr[i].children && _fn(arr[i].children, arr[i]);
    }
    if (result) return;
  }
  _fn(list, null);
  let tmp = [];
  if (!result) return null;
  while (result) {
    tmp.unshift(result.id);
    result = result[_p];
  }
  return tmp;
}
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
43
44

# 第 93 题:给定两个大小为 m 和 n 的有序数组 nums1 和 nums2。请找出这两个有序数组的中位数。要求算法的时间复杂度为 O(log(m+n))。

/**
 * @param {number[]} nums1
 * @param {number[]} nums2
 * @return {number}
 */
var findMedianSortedArrays = function(nums1, nums2) {
  if (nums1.length > nums2.length) [nums1, nums2] = [nums2, nums1];

  const length1 = nums1.length;
  const length2 = nums2.length;
  let min = 0;
  let max = length1;
  let half = Math.floor((length1 + length2 + 1) / 2);
  while (max >= min) {
    const i = Math.floor((max + min) / 2);
    const j = half - i;
    if (i > min && nums1[i - 1] > nums2[j]) {
      max = i - 1;
    } else if (i < max && nums1[i] < nums2[j - 1]) {
      min = i + 1;
    } else {
      let left, right;
      if (i === 0) left = nums2[j - 1];
      else if (j === 0) left = nums1[i - 1];
      else left = Math.max(nums1[i - 1], nums2[j - 1]);

      if (i === length1) right = nums2[j];
      else if (j === length2) right = nums1[i];
      else right = Math.min(nums1[i], nums2[j]);

      return (length1 + length2) % 2 ? left : (left + right) / 2;
    }
  }
  return 0;
};
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

# 第 94 题:vue 在 v-for 时给每项元素绑定事件需要用事件代理吗?为什么?

# 第 95 题:模拟实现一个深拷贝,并考虑对象相互引用以及 Symbol 拷贝的情况

# 第 96 题:介绍下前端加密的常见场景和方法

# 第 97 题:React 和 Vue 的 diff 时间复杂度从 O(n^3) 优化到 O(n) ,那么 O(n^3) 和 O(n) 是如何计算出来的?

# 第 98 题:(京东)写出如下代码的打印结果

function changeObjProperty(o) {
  o.siteUrl = "http://www.baidu.com";
  o = new Object();
  o.siteUrl = "http://www.google.com";
}
let webSite = new Object();
changeObjProperty(webSite);
console.log(webSite.siteUrl);
// http://www.baidu.com
1
2
3
4
5
6
7
8
9

# 第 99 题:(bilibili)编程算法题

function fun(num) {
  let num1 = num / 10;
  let num2 = num % 10;
  if (num1 < 1) {
    return num;
  } else {
    num1 = Math.floor(num1);
  }
  return `${num2}${fun(num1)}`;
}
var a = fun(12345);
console.log(a);
console.log(typeof a);
1
2
3
4
5
6
7
8
9
10
11
12
13

# 第 100 题:(京东)请写出如下代码的打印结果

function Foo() {
  Foo.a = function() {
    console.log(1);
  };
  this.a = function() {
    console.log(2);
  };
}
// 以上只是 Foo 的构建方法,没有产生实例,此刻也没有执行

Foo.prototype.a = function() {
  console.log(3);
};
// 现在在 Foo 上挂载了原型方法 a ,方法输出值为 3

Foo.a = function() {
  console.log(4);
};
// 现在在 Foo 上挂载了直接方法 a ,输出值为 4

Foo.a();
// 立刻执行了 Foo 上的 a 方法,也就是刚刚定义的,所以
// # 输出 4

let obj = new Foo();
/* 这里调用了 Foo 的构建方法。Foo 的构建方法主要做了两件事:
1. 将全局的 Foo 上的直接方法 a 替换为一个输出 1 的方法。
2. 在新对象上挂载直接方法 a ,输出值为 2。
*/

obj.a();
// 因为有直接方法 a ,不需要去访问原型链,所以使用的是构建方法里所定义的 this.a,
// # 输出 2

Foo.a();
// 构建方法里已经替换了全局 Foo 上的 a 方法,所以
// # 输出 1

// 4 2 1
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