前端面试每日3+2(第28天)

12/29/2019 每日3+2

当你发现自己的才华撑不起你的野心时,就请安静下来学习吧!

鲁迅说过:答案仅供参考...

# 1、请分别用深度优先思想和广度优先思想实现一个拷贝函数?


解析:

# 低配版

// 递归拷贝 (类型判断)
function deepClone(value,hash = new WeakMap){ // 弱引用,不要用map。防止内存泄露
    // weakMap的key值只能是对象。map的key可以是对象,可以是字符串等
    // null 和 undefiend 是不需要拷贝的
    if(value == null){ return value;}
    if(value instanceof RegExp){return new RegExp(value)}
    if(value instanceof Date){return new Date(value)}
    // 普通值,函数是不需要拷贝
    if(typeof value != 'object') return value;
    let obj = new value.constructor(); // [] {}
    // 说明是一个对象类型 。 防止循环拷贝。
    if(hash.get(value)){
        return hash.get(value)
    }
    hash.set(value,obj); // 弱引用 key为对象。弱引用变量销毁,
    for(let key in value){ // in 会遍历当前对象上的属性 和 __proto__指代的属性
        // 补考呗 对象的__proto__上的属性
        if(value.hasOwnProperty(key)){
            // 如果值还有可能是对象 就继续拷贝
            obj[key] = deepClone(value[key],hash);
        }
    }
    return obj
    // 区分对象和数组 Object.prototype.toString.call
}
// null / undefined
let o = {};
o.x = o;
let o1 = deepClone(o); // 如果这个对象拷贝过了 就返回那个拷贝的结果就可以了
console.log(o1);
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

# 高配版

// 工具函数
let _toString = Object.prototype.toString
let map = {
  array: 'Array',
  object: 'Object',
  function: 'Function',
  string: 'String',
  null: 'Null',
  undefined: 'Undefined',
  boolean: 'Boolean',
  number: 'Number'
}
let getType = (item) => {
  return _toString.call(item).slice(8, -1)
}
let isTypeOf = (item, type) => {
  return map[type] && map[type] === getType(item)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

深度优先遍历

let DFSdeepClone = (obj, visitedArr = []) => {
  let _obj = {}
  if (isTypeOf(obj, 'array') || isTypeOf(obj, 'object')) {
    let index = visitedArr.indexOf(obj)
    _obj = isTypeOf(obj, 'array') ? [] : {}
    if (~index) { // 判断环状数据
      _obj = visitedArr[index]
    } else {
      visitedArr.push(obj)
      for (let item in obj) {
        _obj[item] = DFSdeepClone(obj[item], visitedArr)
      }
    }
  } else if (isTypeOf(obj, 'function')) {
    _obj = eval('(' + obj.toString() + ')');
  } else {
    _obj = obj
  }
  return _obj
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

广度优先遍历

let BFSdeepClone = (obj) => {
    let origin = [obj],
      copyObj = {},
      copy = [copyObj]
      // 去除环状数据
    let visitedQueue = [],
      visitedCopyQueue = []
    while (origin.length > 0) {
      let items = origin.shift(),
        _obj = copy.shift()
      visitedQueue.push(items)
      if (isTypeOf(items, 'object') || isTypeOf(items, 'array')) {
        for (let item in items) {
          let val = items[item]
          if (isTypeOf(val, 'object')) {
            let index = visitedQueue.indexOf(val)
            if (!~index) {
              _obj[item] = {}
                //下次while循环使用给空对象提供数据
              origin.push(val)
                // 推入引用对象
              copy.push(_obj[item])
            } else {
              _obj[item] = visitedCopyQueue[index]
              visitedQueue.push(_obj)
            }
          } else if (isTypeOf(val, 'array')) {
            // 数组类型在这里创建了一个空数组
            _obj[item] = []
            origin.push(val)
            copy.push(_obj[item])
          } else if (isTypeOf(val, 'function')) {
            _obj[item] = eval('(' + val.toString() + ')');
          } else {
            _obj[item] = val
          }
        }
        // 将已经处理过的对象数据推入数组 给环状数据使用
        visitedCopyQueue.push(_obj)
      } else if (isTypeOf(items, 'function')) {
        copyObj = eval('(' + items.toString() + ')');
      } else {
        copyObj = obj
      }
    }
  return copyObj
}
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
45
46
47

参考答案 (opens new window) --- 感谢【Daily-Interview-Question】 (opens new window)

# 2、ES5/ES6 的继承除了写法以外还有什么区别?


解析:

  1. class声明会提升,但是不会初始化赋值。
  2. class声明内部会启用严格模式。
  3. class的所有方法(包括静态方法和实例方法)都是不可枚举的。
  4. class的所有(包括静态方法和实例方法)都没有原型对象prototype,所以也没有[[construct]],不能使用new来调用。
  5. 必须要用new调用class。
  6. class内部无法重写类名。

参考答案 (opens new window) --- 感谢【Daily-Interview-Question】 (opens new window)

# 3、setTimeout、Promise、Async/Await 的区别?

解析:

参考答案 (opens new window) --- 感谢【Daily-Interview-Question】 (opens new window)

# 4、(头条、微医)Async/Await 如何通过同步的方式实现异步?

解析:

参考答案 (opens new window) --- 感谢【Daily-Interview-Question】 (opens new window)

# 5、(头条)异步笔试题

请写出下面代码的运行结果

async function async1() {
    console.log('async1 start');
    await async2();
    console.log('async1 end');
}
async function async2() {
    console.log('async2');
}
console.log('script start');
setTimeout(function() {
    console.log('setTimeout');
}, 0)
async1();
new Promise(function(resolve) {
    console.log('promise1');
    resolve();
}).then(function() {
    console.log('promise2');
});
console.log('script end');
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

解析:

参考答案 (opens new window) --- 感谢【Daily-Interview-Question】 (opens new window)

Last Updated: 1/14/2020, 7:56:38 AM
    asphyxia
    逆时针向