第 1 题:(滴滴、饿了么)写 React / Vue 项目时为什么要在列表组件中写 key,其作用是什么?
不带有key,并且使用简单的模板,基于这个前提下,可以更有效的复用节点,diff速度来看也是不带key更加快速的,因为带key在增删节点上有耗时。这就是vue文档所说的默认模式。但是这个并不是key作用,而是没有key的情况下可以对节点就地复用,提高性能。这种模式会带来一些隐藏的副作用,比如可能不会产生过渡效果,或者在某些节点有绑定数据(表单)状态,会出现状态错位。VUE文档也说明了。还有就是key的作用是为了在diff算法执行时更快的找到对应的节点,提高diff速度,但是这个含有争议。
第 2 题:`['1', '2', '3'].map(parseInt)` what & why ?
结果: [1, NaN, NaN]
计算会被转化为:
['1', '2', '3'].map((item, index) => {
return parseInt(item, index)
})
parseInt(string, radix)
radix 代表进制
没有1进制
3不是2进制
第 3 题:(挖财)什么是防抖和节流?有什么区别?如何实现?
1.防抖
触发高频事件后 n 秒内函数只会执行一次,如果 n 秒内高频事件再次被触发,则重新计算时间
思路: 每次触发事件时都取消之前的延时调用方法,新建延时
2.节流
高频事件触发,但在 n 秒内只会执行一次,所以节流会稀释函数的执行频率
思路: 每次触发事件时都判断当前是否有等待执行的延时函数
第 4 题:介绍下 Set、Map、WeakSet 和 WeakMap 的区别?
Set: 成员不能重复;只有健值,没有健名,有点类似数组;可以遍历,方法有add, delete,has
const set = new Set([1, 2, 3, 4, 4]);
weakSet: 成员都是对象;成员都是弱引用,随时可以消失。 可以用来保存DOM节点,不容易造成内存泄漏;不能遍历,方法有add, delete,has
Map: 本质上是健值对的集合,类似集合;可以遍历,方法很多,可以跟各种数据格式转换
const map = new Map([
['name', '张三'],
['title', 'Author']
]);
weakMap: 直接受对象作为健名(null除外),不接受其他类型的值作为健名;健名所指向的对象,不计入垃圾回收机制;不能遍历,方法同get,set,has,delete
第 5 题:介绍下深度优先遍历和广度优先遍历,如何实现?
深度优先遍历(DFS),广度优先遍历(BFS),BFS和DFS都是图的算法之一,主要用以处理树状结构,在前端用于搜索dom树,遍历object
深度:
function deepFirstSearch(node,nodeList) {
if (node) {
nodeList.push(node);
var children = node.children;
for (var i = 0; i < children.length; i++)
deepFirstSearch(children[i],nodeList);
}
return nodeList;
}
广度:
function breadthFirstSearch(node,nodeList) {
var i = 0;
if (!(node == null)) {
nodeList.push(node);
breadthFirstSearch(node.nextElementSibling,nodeList);
breadthFirstSearch(node.firstElementChild,nodeList);
}
return nodeList;
}
第 6 题:请分别用深度优先思想和广度优先思想实现一个拷贝函数?
var obj = {
a: 1,
b: {
c: 2
}
}
//深度优先伪代码
function deepCopy (obj, new_obj_child) {
var new_obj = new_obj_child || {};
for (var i in obj) {
if (typeof obj[i] == 'object') {
new_obj[i] = {}
copy(obj[i], new_obj[i])
} else {
new_obj[i] = obj[i]
}
}
return new_obj
}
//广度优先伪代码
function broadCopy (obj, new_obj_child) {
var new_obj = new_obj_child || {};
for (var i in obj) {
if (typeof obj[i] == 'object') {
new_obj[i] = {}
} else {
new_obj[i] = obj[i]
}
}
for (var i in obj) {
if (typeof obj[i] == 'object') {
broadCopy(obj[i], new_obj[i])
}
}
return new_obj
}
第 7 题:ES5/ES6 的继承除了写法以外还有什么区别?
function AA () {
this.aa = 'aa'
}
AA.prototype.getAA = function() {
console.log(this)
return this.aa
}
function BB() {
AA.call(this)
}
BB.prototype = new AA()
BB.prototype.constructor = BB
let bb = new BB()
bb.getAA()
ES5的继承实质上是先创建子类的实例对象,然后再将父类的方法添加到this上(Parent.apply(this)),然后再把原型链继承
class AA {
constructor() {
this.aa = 'aa'
}
getAA() {
console.log(this)
return this.aa
}
}
class BB extends AA {
constructor() {
super()
}
}
let bb = new BB()
bb.getAA()
ES6的继承机制完全不同,实质上是先创建父类的实例对象this(所以必须先调用父类的super()方法,才可使用this关键字,否则报错。),然后再用子类的构造函数修改this实现继承
第 8 题:setTimeout、Promise、Async/Await 的区别
setTimeout 为定时器,定时器到期,执行函数或一段代码
Promise 对象用于表示一个异步操作最终完成及其结果
var promise1 = new Promise(function(resolve, reject) {
setTimeout(function() {
resolve('foo');
}, 300);
});
promise1.then(function(value) {
console.log(value);
});
console.log(promise1);
async用来定义一个返回AsyncFunction对象的异步函数,他会通过一个隐式Promise返回结果,且写法更像同步函数
function resolveAfter2Seconds() {
return new Promise(resolve => {
setTimeout(() => {
resolve('resolved');
}, 2000);
});
}
async function asyncCall() {
console.log('calling');
var result = await resolveAfter2Seconds();
console.log(result);
}
asyncCall();
第 9 题:(头条、微医)Async/Await 如何通过同步的方式实现异步
async 函数就是 Generator 函数的语法糖。async 函数就是将 Generator 函数的星号(*)替换成 async,将 yield 替换成 await
async比generator改进有自带执行器,更好的语义,更广的适用性
generator利用"协程"(coroutine),意思是多个线程互相协作,完成异步任务。协程最大优点就是代码的写法非常像同步操作.
async异步函数可以包含await指令,该指令会暂停异步函数的执行(即交出执行权),它调用的函数会继续执行, await收到异步函数返回的隐式Promise/原始值,然后继续执行async函数,并返回结果
第 10 题:(头条)异步笔试题
async function async1() {
console.log('async1 start'); //2
await async2();
console.log('async1 end'); //9
}
async function async2() {
console.log('async2 start'); //3
await async3();
console.log('async2 end'); //7
}
async function async3(){
console.log("async3") //4
}
console.log('script start'); //1
setTimeout(function() {
console.log('setTimeout'); //10
}, 0)
async1();
new Promise(function(resolve) {
console.log('promise1'); //5
resolve();
}).then(function() {
console.log('promise2'); //8
});
console.log('script end'); //6
考察:同步异步,宏任务微任务执行顺序
靳肖健