前端面试每日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
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
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
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
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 的继承除了写法以外还有什么区别?
解析:
- class声明会提升,但是不会初始化赋值。
- class声明内部会启用严格模式。
- class的所有方法(包括静态方法和实例方法)都是不可枚举的。
- class的所有(包括静态方法和实例方法)都没有原型对象prototype,所以也没有
[[construct]]
,不能使用new
来调用。 - 必须要用
new
调用class。 - 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
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)