FE

128 阅读4分钟

1、为什么要用 setTimeout 模拟 setInterval,以及代码实现 ?

每个 setTimeout 产生的任务会直接 push 到任务队列中;而 setInterval 在每次把任务 push 到任务队列前,
都要进行一下判断(看上次的任务是否仍在队列中,如果有则不添加,没有则添加
let timer = null
  interval(func, wait){
  let interv = function(){
  func.call(null);
  timer=setTimeout(interv, wait);
  };
  timer= setTimeout(interv, wait);
  }

2、如何实现一个深拷贝(考虑循环引用对象、和symbol类型)?

 方法一:
 function cloneDeep4(source, hash = new WeakMap()) {
    if (!isObject(source)) return source; 
    if (hash.has(source)) return hash.get(source); 
    let target = Array.isArray(source) ? [] : {};
    hash.set(source, target);
    let symKeys = Object.getOwnPropertySymbols(source); // 查找
    if (symKeys.length) { // 查找成功	
        symKeys.forEach(symKey => {
            if (isObject(source[symKey])) {
                target[symKey] = cloneDeep4(source[symKey], hash); 
            } else {
                target[symKey] = source[symKey];
            }    
        });
    }
    for(let key in source) {
        if (Object.prototype.hasOwnProperty.call(source, key)) {
            if (isObject(source[key])) {
                target[key] = cloneDeep4(source[key], hash); 
            } else {
                target[key] = source[key];
            }
        }
    }
    return target;
}
方法二:
 function cloneDeep4(source, hash = new WeakMap()) {
    if (!isObject(source)) return source; 
    if (hash.has(source)) return hash.get(source); 
    let target = Array.isArray(source) ? [] : {};
    hash.set(source, target);
    Reflect.ownKeys(source).forEach(key => {
    if (isObject(source[key])) {
        target[key] = cloneDeep4(source[key], hash); 
    } else {
        target[key] = source[key];
    }  
    });
    return target;
}

3、修改this指向的方法以及区别,箭头函数可以修改this指向吗,为什么?

call,apply,bind;
call,apply的区别是,第二个参数,apply接受一个数组,call是有多少个参数,就依次的写多少个就行。
bind和call,apply的区别是:bind的返回函数不会立即执行,而call,apply的会。
bind的第二个参数和call的第二个参数一样。

4、 浏览器的垃圾回收,以及v8引擎的垃圾回收?

浏览器的垃圾回收:1、标记清楚;2、引用计数;
v8引擎的:
栈内存:调用栈上下文切换后被回收;
堆内存:
    ·新生代内存回收机制:
        新生代内存容量小,64位系统下仅有32M。新生代内存分为FromTo两部分,
        进行垃圾回收时,先扫描From,将非存活对象回收,将存活对象顺序复制到To中,
        之后调换From/To,等待下一次回收

    ·老生代内存回收机制

        晋升:如果新生代的变量经过多次回收依然存在,
                那么就会被放入老生代内存中
        标记清除:老生代内存会先遍历所有对象并打上标记,
                    然后对正在使用或被强引用的对象取消标记,回收被标记的对象
        整理内存碎片:把对象挪到内存的一端

5、js的数据类型有哪些?基础数据类型和复杂数据类型的区别?判断数据类型的方法以及原理?

  ·基本数据类型:BooleanUndefinedNullNumberBigIntString, Symbol
  ·引用(复杂)数据类型:object
  区别:
      基本数据类型存储在:栈内存
      引用数据类型存储在:引用地址存储在栈内存,实际值存储在堆内存。
  方法以原理:
      instanceof; 
          只要右边变量的 prototype 在左边变量的原型链上即可
      constructor;
          当一个函数F被定义时,JS引擎会为F添加prototype原型,
          然后再在prototype上添加一个constructor属性,并让其指向F的引用
      typeof(这个可以不说原理);
          typeof 目前能返回stringnumberbooleansymbolbigintundefinedobjectfunction这八种判断类型
      Object.prototype.toString(这个是判断类型最准的方法)
          toString是Object原型对象上的一个方法,该方法默认返回其调用者的具体类型,
          更严格的讲,是 toString运行时this指向的对象类型, 
          返回的类型格式为[object,xxx],xxx是具体的数据类型

6、浏览器的事件机制

  大致:一串js代码,从上而下执行,同步任务直接执行,异步任务会有宏任务和微任务。
  在这过程中,宏任务会放到宏任务队列,微任务会放到微任务队列。
  当同步代码执行完毕后,会先将微任务队列里面的微任务执行清空,
  然后再去宏任务队列拿一个宏任务执行,
  在这执行过程中,有微任务,就将它放到微任务队列,
  等该宏任务执行完毕,再执行微任务队列里面的任务,直到清空,
  再去宏任务队列,拿去一个宏任务,依次循环。
  
  看代码说出打印结果:
  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')
      new Promise(function (resolve) {
        console.log('setTimeout - promise1');
        resolve()
      }).then(function () {
        console.log('setTimeout - promise2')
        new Promise(function (resolve) {
          console.log('setTimeout - setTimeout - promise1');
          resolve()
        }).then(function () {
          console.log('setTimeout - setTimeout - promise2')
        });
      });
    }, 0);

    setTimeout(function () {
      console.log('setTimeout2')
    }, 0);
    async1();
    new Promise(function (resolve) {
      console.log('promise1');
      resolve()
    }).then(function () {
      console.log('promise2')
    });
    console.log('script end')
结果:
script start
async1 start
async2
promise1
script end
async1 end
promise2
setTimeout
setTimeout - promise1
setTimeout - promise2
setTimeout - setTimeout - promise1
setTimeout - setTimeout - promise2
setTimeout2

7、css 的伪类和伪元素有哪些?有什么区别?

8、webpack 优化的手段

9、webpack的热更新原理

10、react diff算法

11、react常用的hooks

12、react的性能优化

13、useMemo,useCallback,react.memo的区别

14、调用setState之后发生了什么

15、前端常用的性能优化

16、http2和http1.1的比较

17、webpack动态加载的原理

18、promise.all是什么?如果有一个失败了,其他没有失败,还要想得到结果怎么办?

20、mp.weixin.qq.com/s/hXQnMfnNe…

21、为什么会出现跨域问题,怎么解决?

22、说一下浏览器的缓存

23、怎么做响应式开发

24、输入url之后发生了什么

25、ts中interface和type的区别

  [https://blog.csdn.net/glorydx/article/details/112625953](https://blog.csdn.net/glorydx/article/details/112625953)