You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
function createKeyToOldIdx (children, beginIdx, endIdx) {
let i, key
const map = {}
for (i = beginIdx; i <= endIdx; ++i) {
key = children[i].key
if (isDef(key)) map[key] = i
}
return map
}
遍历寻找:
// sameVnode 是对比新旧节点是否相同的函数
function findIdxInOld (node, oldCh, start, end) {
for (let i = start; i < end; i++) {
const c = oldCh[i]
if (isDef(c) && sameVnode(node, c)) return i
}
}
深度优先遍历(Depth-First-Search),是搜索算法的一种,它沿着树的深度遍历树的节点,尽可能深地搜索树的分支。当节点 v 的所有边都已被探寻过,将回溯到发现节点 v 的那条边的起始节点。这一过程一直进行到已探寻源节点到其他所有节点为止,如果还有未被发现的节点,则选择其中一个未被发现的节点为源节点并重复以上操作,直到所有节点都被探寻完成。
\1. 写 React/Vue 项目时为什么要在组件中写 key,其作用是什么?
key 的作用是为了在 diff 算法执行时更快的找到对应的节点,提高 diff 速度。
vue 和 react 都是采用 diff 算法来对比新旧虚拟节点,从而更新节点。在 vue 的 diff 函数中。可以先了解一下 diff 算法。
在交叉对比的时候,当新节点跟旧节点
头尾交叉对比
没有结果的时候,会根据新节点的 key 去对比旧节点数组中的 key,从而找到相应旧节点(这里对应的是一个 key => index 的 map 映射)。如果没找到就认为是一个新增节点。而如果没有 key,那么就会采用一种遍历查找的方式去找到对应的旧节点。一种一个 map 映射,另一种是遍历查找。相比而言。map 映射的速度更快。vue 部分源码如下:
创建 map 函数:
遍历寻找:
本题链接:
Advanced-Frontend/Daily-Interview-Question#1
\2. 解析 ['1', '2', '3'].map(parseInt)
第一眼看到这个题目的时候,脑海跳出的答案是 [1, 2, 3],但是 真正的答案是 [1, NaN, NaN]。
这个 callback 一共可以接收三个参数,其中第一个参数代表当前被处理的元素,而第二个参数代表该元素的索引。
parseInt(string, radix)
接收两个参数,第一个表示被处理的值(字符串),第二个表示为解析时的基数。了解这两个函数后,我们可以模拟一下运行情况;
parseInt('1', 0) //radix 为 0 时,且 string 参数不以“0x”和“0”开头时,按照 10 为基数处理。这个时候返回 1;
parseInt('2', 1) // 基数为 1(1 进制)表示的数中,最大值小于 2,所以无法解析,返回 NaN;
parseInt('3', 2) // 基数为 2(2 进制)表示的数中,最大值小于 3,所以无法解析,返回 NaN。
map 函数返回的是一个数组,所以最后结果为 [1, NaN, NaN]。
最后附上 MDN 上对于这两个函数的链接,具体参数大家可以到里面看:
本题链接:
Advanced-Frontend/Daily-Interview-Question#4
\3. 什么是防抖和节流?有什么区别?如何实现?
本题链接:
Advanced-Frontend/Daily-Interview-Question#5
\4. 介绍下 Set、Map、WeakSet 和 WeakMap 的区别?
Set
WeakSet
Map
WeakMap
本题链接:
Advanced-Frontend/Daily-Interview-Question#6
\5. 介绍下深度优先遍历和广度优先遍历,如何实现?
深度优先遍历(DFS)
深度优先遍历(Depth-First-Search),是搜索算法的一种,它沿着树的深度遍历树的节点,尽可能深地搜索树的分支。当节点 v 的所有边都已被探寻过,将回溯到发现节点 v 的那条边的起始节点。这一过程一直进行到已探寻源节点到其他所有节点为止,如果还有未被发现的节点,则选择其中一个未被发现的节点为源节点并重复以上操作,直到所有节点都被探寻完成。
简单的说,DFS 就是从图中的一个节点开始追溯,直到最后一个节点,然后回溯,继续追溯下一条路径,直到到达所有的节点,如此往复,直到没有路径为止。
DFS 可以产生相应图的拓扑排序表,利用拓扑排序表可以解决很多问题,例如最大路径问题。一般用堆数据结构来辅助实现 DFS 算法。
注意:深度 DFS 属于盲目搜索,无法保证搜索到的路径为最短路径,也不是在搜索特定的路径,而是通过搜索来查看图中有哪些路径可以选择。
步骤:
实现:
测试:
测试成功。
广度优先遍历(BFS)
广度优先遍历(Breadth-First-Search)是从根节点开始,沿着图的宽度遍历节点,如果所有节点均被访问过,则算法终止,BFS 同样属于盲目搜索,一般用队列数据结构来辅助实现 BFS。
BFS 从一个节点开始,尝试访问尽可能靠近它的目标节点。本质上这种遍历在图上是逐层移动的,首先检查最靠近第一个节点的层,再逐渐向下移动到离起始节点最远的层。
步骤:
创建一个队列,并将开始节点放入队列中;
若队列非空,则从队列中取出第一个节点,并检测它是否为目标节点;
若队列为空,表示图中并没有目标节点,则结束遍历。
实现:
测试:
测试成功。
本题链接:
Advanced-Frontend/Daily-Interview-Question#9
\6. 异步笔试题
请写出下面代码的运行结果:
题目的本质,就是考察
setTimeout
、promise
、async await
的实现及执行顺序,以及 JS 的事件循环的相关问题。答案:
过程详解链接:
Advanced-Frontend/Daily-Interview-Question#7
\7. 将数组扁平化并去除其中重复数据,最终得到一个升序且不重复的数组
本题链接:
Advanced-Frontend/Daily-Interview-Question#8
8.JS 异步解决方案的发展历程以及优缺点。
1. 回调函数(callback)
缺点:回调地狱,不能用 try catch 捕获错误,不能 return
回调地狱的根本问题在于:
优点:解决了同步的问题(只要有一个任务耗时很长,后面的任务都必须排队等着,会拖延整个程序的执行)。
2. Promise
Promise 就是为了解决 callback 的问题而产生的。
Promise 实现了链式调用,也就是说每次 then 后返回的都是一个全新 Promise,如果我们在 then 中 return ,return 的结果会被 Promise.resolve() 包装。
优点:解决了回调地狱的问题。
缺点:无法取消 Promise ,错误需要通过回调函数来捕获。
3. Generator
特点:可以控制函数的执行,可以配合 co 函数库使用。
4. Async/await
async、await 是异步的终极解决方案。
优点是:代码清晰,不用像 Promise 写一大堆 then 链,处理了回调地狱的问题;
缺点:await 将异步代码改造成同步代码,如果多个异步操作没有依赖性而使用 await 会导致性能上的降低。
下面来看一个使用
await
的例子:对于以上代码你可能会有疑惑,让我来解释下原因:
b
先执行,在执行到await 10
之前变量a
还是 0,因为await
内部实现了generator
,generator 会保留堆栈中东西,所以这时候 a = 0 被保存了下来;await
是异步操作,后来的表达式不返回Promise
的话,就会包装成Promise.reslove(返回值)
,然后会去执行函数外的同步代码;a = 0 + 10
。上述解释中提到了
await
内部实现了generator
,其实await
就是generator
加上Promise
的语法糖,且内部实现了自动执行generator
。如果你熟悉 co 的话,其实自己就可以实现这样的语法糖。本题链接:
Advanced-Frontend/Daily-Interview-Question#11
\9. 谈谈你对 TCP 三次握手和四次挥手的理解
本题链接:
Advanced-Frontend/Daily-Interview-Question#15
The text was updated successfully, but these errors were encountered: