面试题学习1-5

128 阅读5分钟

第 1 题:写 React / Vue 项目时为什么要在列表组件中写 key,其作用是什么?

答:提高组件渲染的准确性。(保证组件状态正确)

key用做 Vue 的虚拟 DOM 算法的提示,以在比对新旧节点组时辨识 VNodes。
更新组件时**判断两个节点是否相同**。相同就复用,不相同就删除旧的创建新的。
如果不使用 key,Vue 会使用一种算法来最小化元素的移动并且尽可能尝试就地修改/复用相同类型元素。而使用     key 时,它会基于 key 的顺序变化重新排列元素,并且那些使用了已经不存在的 key 的元素将会被移除/销毁。
有相同父元素的子元素必须有**唯一的 key**。重复的 key 会造成渲染错误。

第 2 题:['1', '2', '3'].map(parseInt) what & why ?

答:输出[1, NaN, NaN]。

    array.map(function(currentValue,index,arr), thisValue)
    参数说明:
    currentValue 必须 当前元素值; 
    index 可选 当前元素的索引值;
    arr 可选 当前元素属于的数组对象;
    thisValue 可选。对象作为该执行回调时使用,传递给函数,用作 "this" 的值。如果省略了 thisValue,或者传入 nullundefined,那么回调函数的 this 为全局对象。
    
    parseInt(string, radix) 接收两个参数,第一个表示被处理的值(字符串),第二个表示为解析时的基数,即进制数。
    radix | 可选。表示要解析的数字的基数。该值介于 2 ~ 36 之间,否则ParseInt()返回NaN

第 3 题:什么是防抖和节流?有什么区别?如何实现?

答:① 防抖:触发高频事件后n秒内函数只会执行一次,如果n秒内高频事件再次被触发,则重新计算时间

//思路: 每次触发事件时都取消之前的延时调用方法
function debounce(fn) {
      let timeout = null; // 创建一个标记用来存放定时器的返回值
      return function () {
        clearTimeout(timeout); // 每当用户输入的时候把前一个 setTimeout clear 掉
        timeout = setTimeout(() => { // 然后又创建一个新的 setTimeout, 这样就能保证输入字符后的 interval 间隔内如果还有字符输入的话,就不会执行 fn 函数
          fn.apply(this, arguments);
        }, 500);
      };
    }
    function sayHi() {
      console.log('防抖成功');
    }

    var inp = document.getElementById('inp');
    inp.addEventListener('input', debounce(sayHi)); // 防抖

节流: 高频事件触发,但在n秒内只会执行一次,所以节流会稀释函数的执行频率

//思路:每次触发事件时都判断当前是否有等待执行的延时函数
function throttle(fn) {
      let canRun = true; // 通过闭包保存一个标记
      return function () {
        if (!canRun) return; // 在函数开头判断标记是否为true,不为true则return
        canRun = false; // 立即设置为false
        setTimeout(() => { // 将外部传入的函数的执行放在setTimeout中
          fn.apply(this, arguments);
          // 最后在setTimeout执行完毕后再把标记设置为true(关键)表示可以执行下一次循环了。当定时器没有执行的时候标记永远是false,在开头被return掉
          canRun = true;
        }, 500);
      };
    }
    function sayHi(e) {
      console.log(e.target.innerWidth, e.target.innerHeight);
    }
    window.addEventListener('resize', throttle(sayHi));

第 4 题:介绍下 Set、Map、WeakSet 和 WeakMap 的区别?

答:Set是集合 [值,值] 的数据结构,Map是字典 [键,值] 的数据结构,二者都用于数据重组和数据储存。

Set:
1.  成员不能重复;
2.  只有健值,没有健名,有点类似数组;
3.  可以遍历,方法有add, delete,has。
weakSet:
1.  成员都是对象;
2.  成员都是弱引用,随时可以消失。 可以用来保存DOM节点,不容易造成内存泄漏;
3.  不能遍历,方法有add, delete,has。
Map:
1.  本质上是健值对的集合,类似集合;
2.  可以遍历,方法很多,可以干跟各种数据格式转换。
weakMap:
1.  直接受对象作为健名(null除外),不接受其他类型的值作为健名;
2.  健名所指向的对象,不计入垃圾回收机制;
3.  不能遍历,方法同get,set,has,delete。

第 5 题:介绍下深度优先遍历和广度优先遍历,如何实现?

深度优先遍历DFS(Depth-First-Search),是搜索算法的一种,它沿着树的深度遍历树的节点,尽可能深地搜索树的分支。当节点v的所有边都已被探寻过,将回溯到发现节点v的那条边的起始节点。这一过程一直进行到已探寻源节点到其他所有节点为止,如果还有未被发现的节点,则选择其中一个未被发现的节点为源节点并重复以上操作,直到所有节点都被探寻完成。

广度优先遍历BFS(Breadth-First-Search)是从根节点开始,沿着图的宽度遍历节点,逐层遍历,如果所有节点均被访问过,则算法终止。

深度优先搜索用栈(stack)来实现,整个过程可以想象成一个倒立的树形:

1、把根节点压入栈中。

2、每次从栈中弹出一个元素,搜索所有在它下一级的元素,把这些元素压入栈中。并把这个元素记为它下一级元素的前驱。

3、找到所要找的元素时结束程序。

4、如果遍历整个树还没有找到,结束程序。

广度优先搜索使用队列(queue)来实现,整个过程也可以看做一个倒立的树形:

1、把根节点放到队列的末尾。

2、每次从队列的头部取出一个元素,查看这个元素所有的下一级元素,把它们放到队列的末尾。并把这个元素记为它下一级元素的前驱。

3、找到所要找的元素时结束程序。

4、如果遍历整个树还没有找到,结束程序。