1.写 React / Vue 项目时为什么要在列表组件中写 key,其作用是什么?
我的理解,没有key的时候节点会复用,有key的时候节点不会复用,
1. 更准确,带key不会就地复用
2. 更快,利用key的唯一性生成map对象来获取对应节点,比遍历方式更快。
第 4 题:介绍下 Set、Map、WeakSet 和 WeakMap 的区别?
WeakSet和Set都是构造函数,可以使用new命令创建相应的数据结构,并且值都是唯一的;
WeakSet 与 Set 的区别:
1、WeakSet 的成员只能是对象,而不能是其他类型的值,而 Set 对象的成员可以是任意类型的值;
2、WeakSet 对象中储存的对象值都是被弱引用的,即垃圾回收机制不考虑 WeakSet 对该对象的应用,如果没有其他的变量或属性引用这个对象值,则这个对象将会被垃圾回收掉(不考虑该对象还存在于 WeakSet 中),所以,WeakSet 对象里有多少个成员元素,取决于垃圾回收机制有没有运行,运行前后成员个数可能不一致,遍历结束之后,有的成员可能取不到了(被垃圾回收了);
3、由于以上第二点的原因,es6规定WeakSet不能够被遍历,无法使用keys,values等遍历方法,并且不存在size属性。
Map和WeakMap都是构造函数,用域生成键值对的集合;
Map和WeakMap的区别:
1、WeakMap只接受对象作为键名,不接受其他类型的值作为键名,而Map可以接受任何类型的值作为键名;
2、WeakMap的键名所引用的对象都是弱引用,所以这个对象的其他引用都被清除,垃圾回收机制就会释放这个对象所占用的内存;
3、由于第二点的原因,WeakMap不存在遍历操作,没有size的属性,因为WeakMap的键名是不可预测的,可能在不知道的时间,作为键名的对象就被垃圾回收机制清除;
4、不支持clear方法。
第 5 题:介绍下深度优先遍历和广度优先遍历,如何实现?
深度遍历
function dfc(root){
if(root==null)
return [];
var result = [];//存放遍历结果的数组
var nodeStack = [];//暂存元素的栈
nodeStack.push(root);
while(nodeStack.length>0){
let n = nodeStack.pop();
result.push(n);
let children = n.children;
//要从左到右遍历,所以要反向进栈
for(let i=children.length-1;i>=0;i--){
nodeStack.push(children[i]);
}
}
return result;
}
dfc(document.body);
广度优先遍历
function bfc(root){
if(root==null)
return [];
var result = [];//存放遍历结果的数组
var nodeQueue = [];//暂存元素的队列
nodeQueue .push(root);
while(nodeQueue.length>0){
let n = nodeQueue.shift();
result.push(n);
let children = n.children;
for(let i=0;i<children.length;i++){
nodeQueue.push(children[i]);
}
}
return result;
}
bfc(document.body);
第 7 期:ES5/ES6 的继承除了写法以外还有什么区别?
class
不会函数提升。Foo
进入暂时性死区,类似于let
、const
声明变量。class
声明内部会启用严格模式。-
// 引用一个未声明的变量 function Bar() { baz = 42; // it's ok } const bar = new Bar(); class Foo { constructor() { fol = 42; // ReferenceError: fol is not defined } } const foo = new Foo();
class
的所有方法(包括静态方法和实例方法)都是不可枚举的。class
的所有方法(包括静态方法和实例方法)都没有原型对象 prototype,所以也没有[[construct]]
,不能使用new
来调用。- 必须使用
new
调用class
第 11 题:将数组扁平化并去除其中重复数据,最终得到一个升序且不重复的数组
Array.from(new Set(arr.flat(Infinity))).sort((a,b)=>{ return a-b})
Array.from()方法就是将一个类数组对象或者可遍历对象转换成一个真正的数组。
使用 Infinity 作为深度,展开任意深度的嵌套数组
arr3.flat(Infinity);
第 30 题:请把俩个数组 [A1, A2, B1, B2, C1, C2, D1, D2] 和 [A, B, C, D],合并为 [A1, A2, A, B1, B2, B, C1, C2, C, D1, D2, D]。
let arrA = ["A1", "A2", "B1", "B2", "C1", "C2", "D1", "D2"];
let arrB = ["A", "B", "C", "D"];
arrC = arrA
.map((item) => {
if (item == arrB[0] + 2) {
return [item, arrB.shift()];
} else {
return item;
}
})
.flat();
console.log(arrC);
第 31 题:改造下面的代码,使之输出0 - 9,写出你能想到的所有解法。
for (var i = 0; i< 10; i++){
setTimeout(() => {
console.log(i);
}, 1000)
}
// 解法一:
for (let i = 0; i< 10; i++){
setTimeout(() => {
console.log(i);
}, 1000)
}
//解法二,利用 setTimeout 函数的第三个参数,会作为回调函数的第一个参数传入
for (var i = 0; i < 10; i++) {
setTimeout(i => {
console.log(i);
}, 1000, i)
}
使用迭代的方式实现 flatten 函数 #54
var arr = [1, [2, 3, [4]]];
function faltten() {
while (arr.some((item) => Array.isArray(item))) {
arr = [].concat.apply([], arr);
}
}
faltten(arr);
console.log(arr);
第 38 题:下面代码中 a 在什么情况下会打印 1?
var a = ?; if(a == 1 && a == 2 && a == 3){ conso.log(1); }
var a = {
i: 1,
toString() {
return a.i++;
}
}
if( a == 1 && a == 2 && a == 3 ) {
console.log(1);
}
[] == ![]; // true [] == false --> [] == 0 --> "" == 0 --> 0 == 0
2 == [2]; // true 2 == "2" --> 2 == 2
"" == [null]; // true "" == "" (ps: String([null]) === ""; String(null) === "null")
"0" == false; // true "0" == 0 --> 0 == 0
false == 0; // true 0 == 0
false == ""; // true 0 == "" --> 0 == 0
false == []; // true 0 == [] --> 0 == "" --> 0 == 0
"" == 0; // true 0 == 0
"" == []; // true "" == ""
0 == []; // true 0 == "" --> 0 == 0
空字符串转换成boolen为false,只要字符串有长度,就转换成ture,
对象通过tostring转换成字符串,通过valueof转换成数字,一个对象同时存在valueof和tostring方法,valueof会被优先调用
第 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)