。。。

2019-10-28  本文已影响0人  家有饿犬和聋猫

https://juejin.im/post/5d23e750f265da1b855c7bbe

1 (滴滴、饿了么)写 React / Vue 项目时为什么要在列表组件中写 key,其作用是什么?

react和vue都使用diff算法来对比新旧虚拟节点,从而更新节点。
当新节点和旧节点从头到尾交叉对比没有结果时,会根据新节点的key对比旧节点数组中的key,如果没有找到就认为是新增了一个节点。
如果没有key,那么就会采用循环遍历的方式查找就的节点
在不带key的情况下,节点可以复用,省去dom操作的开销,但是只适用于无状态组件的渲染。
带上dom虽然会增加开销,但是可以保证组件的状态正确,并且用户感受不到差距。

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

返回1,NaN,NaN
因为parseInt有三个参数,第一个是被处理的元素,第二个是该元素的索引。。。
parseInt(“1”,0)按照十进制处理,返回 整数 1
parseInt(“2”,1)按照1进制处理,2 不符合一进制表示法,所以返回NaN
parseInt(“3”,2)按照2进制处理,3不符合二进制表示法,所以返回NaN

3(挖财)什么是防抖和节流?有什么区别?如何实现?

防抖:触发高频事件后n秒后调用一次函数,如果在n秒之内,高频事件再次被触发,则重新计算时间
常见的比如input框输入与文本同步需要防抖
解决思路: 创建一个标记用来存放定时器的返回值,每次事件触发前,都清除之前的延时调用
然后又创建一个新的 setTimeout, 这样就能保证输入字符后的 interval 间隔内如果还有字符输入的话,就不会执行 fn 函数,只有在你停止输入的时候才会执行fn函数

<input id="inpu" />

function debounce(e) {
     let timeout = null; // 创建一个标记用来存放定时器的返回值
     return function () {
       clearTimeout(timeout); // 每当用户输入的时候把前一个 setTimeout clear 掉
       timeout = setTimeout(() => { // 然后又创建一个新的 setTimeout, 这样就能保证输入字符后的 interval 间隔内如果还有字符输入的话,就不会执行 fn 函数
        console.log("e.target.value",e.target.value)
       }, 500);
     };
   }
  

   document.getElementById("inpu").addEventListener("keyup",debounce) // 防抖

节流:高频事件触发,但在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));

比如打王者荣耀,用户高频率点击输出时,机器只周期性输出,1秒输出一次
总结:防抖和节流 都是防止某一时间函数高频率触发,但是他们俩的原理却不同
防抖是每一时间段内只能触发一次,而节流是周期间歇性触发函数

应用场景:
防抖:1.search搜索联想,用户在不断输入值时,用防抖来节约请求资源。

节流:1.鼠标不断点击触发,mousedown(单位时间内只触发一次)。
2.监听滚动事件,比如是否滑到底部自动加载更多,用throttle来判断。

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

Set(集合)
成员唯一、无序且不重复
[value, value],键值与键名是一致的(或者说只有键值,没有键名)
可以遍历,方法有:add、delete、has
WeakSet
成员都是对象
成员都是弱引用,可以被垃圾回收机制回收,可以用来保存DOM节点,不容易造成内存泄漏
不能遍历,方法有add、delete、has
Map (字典)
本质上是键值对的集合,类似集合
可以遍历,方法很多可以跟各种数据格式转换
WeakMap
只接受对象作为键名(null除外),不接受其他类型的值作为键名
键名是弱引用,键值可以是任意的,键名所指向的对象可以被垃圾回收,此时键名是无效的
不能遍历,方法有get、set、has、delete

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

深度遍历就是自上而下的遍历,广度遍历就是逐层遍历
深度遍历有回溯的操作(没有路走了需要回头),
深度优先采用的是堆栈的形式, 即先进后出
广度优先则采用的是队列的形式, 即先进先出

   const data = [
    {
        name: 'a',
        children: [
            { name: 'b', children: [{ name: 'e' }] },
            { name: 'c', children: [{ name: 'f' }] },
            { name: 'd', children: [{ name: 'g' }] },
        ],
    },
    {
        name: 'a2',
        children: [
            { name: 'b2', children: [{ name: 'e2' }] },
            { name: 'c2', children: [{ name: 'f2' }] },
            { name: 'd2', children: [{ name: 'g2' }] },
        ],
    }
]

深度遍历(递归调用)

function  getName(data){
    let result=[];
     data.forEach(
           item=>{
             
            const  maps=(data)=>{
                result.push(data.name)  
                //对象里的数组如果存在就继续调用
                data.children&&data.children.forEach(
                    p=>maps(p)
                )
            }
           
            maps(item)
           }
     )
  return  result.join(",")  
}
    console.log(getName(data))
 //a,a2,b,c,d,b2,c2,d2,e,f,g,e2,f2,g2

广度遍历(数组循环)

function getNames(data){

   let result=[];
   let queue=data ;
   while(queue.length>0){
        [...queue].forEach(
            p=>{
                queue.shift();
                result.push(p.name)
                p.children&&(queue.push(...p.children))
            }
        )
   }
   return result.join(",")
}
console.log(getNames(datad))
//a,a2,b,c,d,b2,c2,d2,e,f,g,e2,f2,g2
6 :请分别用深度优先思想和广度优先思想实现一个拷贝函数?

我不会做

7 ES5/ES6 的继承除了写法以外还有什么区别?

es6 :
class 声明会提升,但不会初始化赋值。Foo 进入暂时性死区,类似于 let、const 声明变量。
class 声明内部会启用严格模式。
class 的所有方法(包括静态方法和实例方法)都没有原型对象 prototype(只有proto),所以也没有[[construct]],不能使用 new 来调用。 class 内部无法重写类名。

8 setTimeout、Promise、Async/Await 的区别

宏观任务和微观任务


image.png

Promise本身是一个立即执行函数,如果带then或者catch,有一步操作功能
async 函数返回一个 Promise 对象,await配合async触发异步操作,控制函数的执行顺序。async可以单独使用,await不可以。

8 (头条、微医)Async/Await 如何通过同步的方式实现异步
 function fun1() {
   console.log(1);
   console.log(2);
}
 function fun2() {
    console.log(3);
    console.log(4);
}
// async 实现的是一个异步操作,await 等待一个异步方法执行完成。
// async内使用await等待async的执行完成,就形成了异步函数的同步实现。
async function fun3() {
  await fun1();
  await console.log(5);
  await fun2();
}
fun3();
9 // 编写一个程序将数组扁平化去并除其中重复部分数据,最终得到一个升序且不重复的数组
 var arr = [ [1, 2, 2], [3, 4, 5, 5], [6, 7, 8, 9, [11, 12, [12, 13, [14] ] ] ], 10];
 写法一:  console.log("整理后", [...new Set(arr.flat(Infinity))].sort((a, b) => a - b))
             //  整理后 (14) [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
写法二 :  数据扁平化写法不同,其他都一样
       1    let arrs = JSON.stringify(arr );
       2    扩展运算符:
            while (ary.some(Array.isArray)) {
                ary = [].concat(...ary);
              }  
      3 递归调用:
               function maps(arr){
            arr.map(
                p =>{ 
                    if(p.constructor ===  Array){
                            return    maps(p)
                    }else{
                        data.push(p)
                    }
                }
         )
        }
           
10 Promise 构造函数是同步执行还是异步执行,那么 then 方法呢?
const promise = new Promise((resolve, reject) => {
  console.log(1)
  resolve()
  console.log(2)
})

promise.then(() => {
  console.log(3)
})

console.log(4)

//执行结果:  1243 

Promise构造函数是同步执行的,then方法是异步执行的
扩展 :

  console.log(1);
  resolve(5);
  console.log(2);
}).then(val => {
  console.log(val);
});

promise.then(() => {
  console.log(3);
});

console.log(4);

setTimeout(function() {
  console.log(6);
});

// 124536

promise是微观任务,setTimeout是宏观任务,先执行微观任务,在执行宏观任务;微观任务里,先执行同步再执行异步 所以结果是 124536

11 如何实现一个 new
// 实现一个new
var Dog = function(name) {
  this.name = name
}
Dog.prototype.bark = function() {
  console.log('wangwang')
}
Dog.prototype.sayName = function() {
  console.log('my name is ' + this.name)
}
let sanmao = new Dog('三毛')
sanmao.sayName()
sanmao.bark()
//打印:  wangwang
// my name is 三毛

new的作用:1 创建一个新对象
2 新对象(实例)的proto指向构造函数的prototype ,实现继承
3 执行构造函数,传递参数,改变this指向 Dog.call(obj, ...args)
4 最后把new出来的对象赋值给 变量sanmao

上一篇 下一篇

猜你喜欢

热点阅读