小知识积累

1、使用JSON.parse(JSON.stringify()) 深拷贝时会出现的问题
      var obj = {
        a: "zs",
        b: undefined,
        c: Symbol("score"),
        d: null,
        e: function () {
          console.log("show");
        },
        f: /a/
      };

      console.log(JSON.parse(JSON.stringify(obj)));

小知识积累_第1张图片

      const obj1 = {
        name: "obj1",
      };
      
      const obj2 = {
        name: "obj2",
        relative: obj1,
      };
      
      obj1.relative = obj2;
      console.log(JSON.parse(JSON.stringify(obj2)));

小知识积累_第2张图片

由上可知:
1、当属性值为undefined、函数、symbol 、正则表达式时该属性会丢失
2、拷贝循环引用对象时会报错

2、useEffect、useLayoutEffect执行顺序
const Child = () => {
  useEffect(() => {
    console.log(1);
  }, []);
  useLayoutEffect(() => {
    console.log(2);
  }, []);
  return null;
};

const Parent = () => {
  useEffect(() => {
    console.log(3);
  }, []);
  useLayoutEffect(() => {
    console.log(4);
  }, []);
  return ;
};

输出结果:
小知识积累_第3张图片
解释:react中会先执行子组件、useLayoutEffect是同步、useEffect是异步, 所以最开始输出子组件的同步任务2,然后把子组件的异步任务回调添加到异步队列,然后回到父组件相同执行。

3、对象遍历顺序问题
      var obj = {
        name: "zs",
        age: 2,
        1: "a",
        0: "c",
      };
      
      console.log(obj);

      for (var k in obj) {
        console.log(k);
      }

小知识积累_第4张图片

由上可知无论是直接输出obj,还是遍历obj,都和我们定义的obj属性顺序不同。所以普通对象是无序的。

4、Map的相关问题:
      var value = new Map();
      value.set(2, "a");
      value.set(0, "b");
      value.set(1, "c");
      value.set(1, "w");
      value.set(null, "d");
      value.set(undefined, "e");
      value.set(undefined, "w");

      console.log(value.get(undefined))
      console.log(value.get(null))
      console.log(value);

小知识积累_第5张图片

由上可知:
1、null和undefined可以作为Map对象的key
2、相同key后设置的会覆盖之前的(包括null、undefined)
3、Map对象的key是有序的,和你插入顺序有关

5、深拷贝循环引用问题:
	// 使用weakmap解决循环引用
	// 优点:
	// 1 .WeakMap来记录对象是否被克隆,主要考虑一下三点。
	//  2 .WeakMap对象是key=>value形式,不会重复记录
	//  3 .WeakMap是弱引用,如果不在使用,空间会直接释放

     function deepCopy (obj, hash= new WeakMap()) {
       // 不是对象(普通值类型/function),null,undefined,正则,Date都会直接返回
       if(obj == null || typeof obj != 'object') {
        return obj
       }
       if(obj instanceof RegExp ) {
          return new RegExp(obj)
       }
       if( obj instanceof Date) {
        return new Date(obj)

       }

       // 判断是否循环引用的(判断属性是不是存在了)
       if(hash.get(obj)) return hash.get(obj)

       let cloneObj = new obj.constructor()

      // 存obj
        hash.set(obj, cloneObj)

       for(let key in obj) {
        // in 循环会遍历原型链的,所以需要判断是否是当前对象的属性
        if(obj.hasOwnProperty(key)) {
          cloneObj[key] = deepCopy(obj[key], hash)
        }
       }

       return cloneObj
     }
6、vue判断数据有没有变化源码
function hasChanged(x, y) {
  if (x === y) {
    return x === 0 && 1 / x !== 1 / y;
  } else {
    return x === x || y === y;
  }
}

疑惑:已经判断了x === y,为什么else里还要判断?

NaN === NaN //false

因为NaN的缘故,如果x为NaN,又给它赋值为NaN,其实是没有变化的, 所以在else中判断x === x就可以知道它是NaN这种情况

疑惑:为什么判断 x === 0 && 1 / x !== 1 / y ?

+0 === -0 //true
1/+0 //Infinity
1/-0 //-Infinity

你可能感兴趣的:(前端面试,javascript)