前端面试题-this,【深夜思考

56 阅读5分钟

前端资料汇总

我一直觉得技术面试不是考试,考前背背题,发给你一张考卷,答完交卷等通知。

首先,技术面试是一个 认识自己 的过程,知道自己和外面世界的差距。

更重要的是,技术面试是一个双向了解的过程,要让对方发现你的闪光点,同时也要 试图去找到对方的闪光点,因为他以后可能就是你的同事或者领导,所以,面试官问你有什么问题的时候,不要说没有了,要去试图了解他的工作内容、了解这个团队的氛围。 找工作无非就是看三点:和什么人、做什么事、给多少钱,要给这三者在自己的心里划分一个比例。 最后,祝愿大家在这并不友好的环境下都能找到自己心仪的归宿。

开源分享:docs.qq.com/doc/DSmRnRG… }) } })


代码解析:  
 第一次 console.log 的时候,获取的到的是旧值,这是因为 value 数据发生变化的时候,Vue 没有立刻去更新 DOM ,而是将修改数据的操作放在了一个异步操作队列中,如果一直修改相同数据,异步操作队列还会进行去重,等待同一事件循环中的所有数据变化完成之后,会将队列中的事件拿来进行处理,进行 DOM 的更新  
 第二次的 console.log 是放到 this.$nextTick 回调函数中的,此时获取到的是新值,是因为 nextTick 的回调函数是在 DOM 更新之后触发的


### 三、nextTick 原理


将传入的回调函数包装成异步任务,异步任务又分微任务和宏任务,为了尽快执行所以优先选择微任务;


nextTick 提供了四种异步方法 Promise.thenMutationObserver、setImmediate、setTimeout(fn,0)


### 源码解读


**源码位置** core/util/next-tick  
**源码并不复杂,三个函数,60几行代码,沉下心去看!**  
*Tips:为了便于理解我调整了源码中 nextTick、timerFunc、flushCallbacks 三个函数的书写顺序*



js 复制代码 import { noop } from 'shared/util' import { handleError } from './error' import { isIE, isIOS, isNative } from './env'

// 上面三行与核心代码关系不大,了解即可 // noop 表示一个无操作空函数,用作函数默认值,防止传入 undefined 导致报错 // handleError 错误处理函数 // isIE, isIOS, isNative 环境判断函数, // isNative 判断某个属性或方法是否原生支持,如果不支持或通过第三方实现支持都会返回 false

export let isUsingMicroTask = false // 标记 nextTick 最终是否以微任务执行

const callbacks = [] // 存放调用 nextTick 时传入的回调函数 let pending = false // 标记是否已经向任务队列中添加了一个任务,如果已经添加了就不能再添加了 // 当向任务队列中添加了任务时,将 pending 置为 true,当任务被执行时将 pending 置为 false //

// 声明 nextTick 函数,接收一个回调函数和一个执行上下文作为参数 // 回调的 this 自动绑定到调用它的实例上 export function nextTick(cb?: Function, ctx?: Object) { let _resolve // 将传入的回调函数存放到数组中,后面会遍历执行其中的回调 callbacks.push(() => { if (cb) { // 对传入的回调进行 try catch 错误捕获 try { cb.call(ctx) } catch (e) { // 进行统一的错误处理 handleError(e, ctx, 'nextTick') } } else if (_resolve) { _resolve(ctx) } })

// 如果当前没有在 pending 的回调,
// 就执行 timeFunc 函数选择当前环境优先支持的异步方法
if (!pending) {
    pending = true
    timerFunc()
}

// 如果没有传入回调,并且当前环境支持 promise,就返回一个 promise
// 在返回的这个 promise.then 中 DOM 已经更新好了,
if (!cb && typeof Promise !== 'undefined') {
    return new Promise(resolve => {
        _resolve = resolve
    })
}

}

// 判断当前环境优先支持的异步方法,优先选择微任务 // 优先级:Promise---> MutationObserver---> setImmediate---> setTimeout // setTimeout 可能产生一个 4ms 的延迟,而 setImmediate 会在主线程执行完后立刻执行 // setImmediate 在 IE10 和 node 中支持

// 当在同一轮事件循环中多次调用 nextTick 时 ,timerFunc 只会执行一次

let timerFunc
// 判断当前环境是否原生支持 promise if (typeof Promise !== 'undefined' && isNative(Promise)) { // 支持 promise const p = Promise.resolve() timerFunc = () => { // 用 promise.then 把 flushCallbacks 函数包裹成一个异步微任务 p.then(flushCallbacks) if (isIOS) setTimeout(noop) // 这里的 setTimeout 是用来强制刷新微任务队列的 // 因为在 ios 下 promise.then 后面没有宏任务的话,微任务队列不会刷新 } // 标记当前 nextTick 使用的微任务 isUsingMicroTask = true

// 如果不支持 promise,就判断是否支持 MutationObserver
// 不是IE环境,并且原生支持 MutationObserver,那也是一个微任务

} else if (!isIE && typeof MutationObserver !== 'undefined' && ( isNative(MutationObserver) || MutationObserver.toString() === '[object MutationObserverConstructor]' )) { let counter = 1 // new 一个 MutationObserver 类 const observer = new MutationObserver(flushCallbacks) // 创建一个文本节点 const textNode = document.createTextNode(String(counter))
// 监听这个文本节点,当数据发生变化就执行 flushCallbacks observer.observe(textNode, { characterData: true }) timerFunc = () => { counter = (counter + 1) % 2 textNode.data = String(counter) // 数据更新 } isUsingMicroTask = true // 标记当前 nextTick 使用的微任务

// 判断当前环境是否原生支持 setImmediate

} else if (typeof setImmediate !== 'undefined' && isNative(setImmediate)) { timerFunc = () => { setImmediate(flushCallbacks) } } else {

// 以上三种都不支持就选择 setTimeout
timerFunc = () => { setTimeout(flushCallbacks, 0) }

}

// 如果多次调用 nextTick,会依次执行上面的方法,将 nextTick 的回调放在 callbacks 数组中 // 最后通过 flushCallbacks 函数遍历 callbacks 数组的拷贝并执行其中的回调 function flushCallbacks() { pending = false
const copies = callbacks.slice(0) // 拷贝一份 callbacks callbacks.length = 0 // 清空 callbacks for (let i = 0; i < copies.length; i++) { // 遍历执行传入的回调 copiesi

最后

除了简历做到位,面试题也必不可少,整理了些题目,前面有117道汇总的面试到的题目,后面包括了HTML、CSS、JS、ES6、vue、微信小程序、项目类问题、笔试编程类题等专题。