【面试题】滴滴前端一面常考vue面试题(1)

components:{
AddCustomerSchedule:(resolve)=>import(“…/components/AddCustomer”) // require([])
}


原理



exportfunction ( Ctor: Class | Function | Object | void, data: ?VNodeData, context: Component, children: ?Array, tag?: string ): VNode | Array | void {
// async component let asyncFactory
if (isUndef(Ctor.cid)) {
asyncFactory = CtorCtor = resolveAsyncComponent(asyncFactory, baseCtor) // 默认调用此函数时返回 undefiend // 第二次渲染时Ctor不为undefined if (Ctor === undefined) {
returncreateAsyncPlaceholder( // 渲染占位符 空虚拟节点
asyncFactory,
data,
context,
children,
tag
)
}
}
}
functionresolveAsyncComponent ( factory: Function, baseCtor: Class ): Class | void {
if (isDef(factory.resolved)) {
// 3.在次渲染时可以拿到获取的最新组件 return factory.resolved
}
const resolve = once((res: Object | Class) => {
factory.resolved = ensureCtor(res, baseCtor)
if (!sync) {
forceRender(true) //2. 强制更新视图重新渲染
} else {
owners.length = 0
}
})
const reject = once(reason => {
if (isDef(factory.errorComp)) {
factory.error = trueforceRender(true)
}
})
const res = factory(resolve, reject)// 1.将resolve方法和reject方法传入,用户调用 resolve方法后
sync = falsereturn factory.resolved
}


#### Vue.js的template编译


简而言之,就是先转化成AST树,再得到的render函数返回VNode(Vue的虚拟DOM节点),详细步骤如下:



> 
>  首先,通过compile编译器把template编译成AST语法树(abstract syntax tree 即 源代码的抽象语法结构的树状表现形式),compile是createCompiler的返回值,createCompiler是用以创建编译器的。另外compile还负责合并option。 
>  



> 
>  然后,AST会经过generate(将AST语法树转化成render funtion字符串的过程)得到render函数,render的返回值是VNode,VNode是Vue的虚拟DOM节点,里面有(标签名、子节点、文本等等) 
>  


### nextTick在哪里使用?原理是?




---


* nextTick 中的回调是在下次 DOM 更新循环结束之后执行延迟回调,用于获得更新后的 DOM


* 在修改数据之后立即使用这个方法,获取更新后的 DOM


* 主要思路就是采用微任务优先的方式调用异步方法去执行 nextTick 包装的方法



> 
>  nextTick 方法主要是使用了宏任务和微任务,定义了一个异步方法.多次调用 nextTick 会将方法存入队列中,通过这个异步方法清空当前队列。所以这个 nextTick 方法就是异步方法 
>  


根据执行环境分别尝试采用


* 先采用Promise


* Promise不支持,再采用MutationObserver


* MutationObserver不支持,再采用setImmediate


* 如果以上都不行则采用setTimeout


* 最后执行flushCallbacks,把callbacks里面的数据依次执行





![](https://img-blog.csdnimg.cn/img_convert/ba3f4bcb026f4fe89acc403d0c3588c8.webp?x-oss-process=image/format,png)



回答范例


1. nextTick 中的回调是在下次 DOM 更新循环结束之后执行延迟回调,用于获得更新后的 DOM


2. Vue有个异步更新策略,意思是如果数据变化,Vue不会立刻更新DOM,而是开启一个队列,把组件更新函数保存在队列中,在同一事件循环中发生的所有数据变更会异步的批量更新。这一策略导致我们对数据的修改不会立刻体现在DOM上,此时如果想要获取更新后的DOM状态,就需要使用nextTick


3. 开发时,有两个场景我们会用到nextTick


* created中想要获取DOM时


* 响应式数据变化后获取DOM更新后的状态,比如希望获取列表更新后的高度


4. nextTick签名如下:function nextTick(callback?: () => void): Promise<void>


所以我们只需要在传入的回调函数中访问最新DOM状态即可,或者我们可以await nextTick()方法返回的Promise之后做这件事


5. 在Vue内部,nextTick之所以能够让我们看到DOM更新后的结果,是因为我们传入的callback会被添加到队列刷新函数(flushSchedulerQueue)的后面,这样等队列内部的更新函数都执行完毕,所有DOM操作也就结束了,callback自然能够获取到最新的DOM值


基本使用



const vm = newVue({
el: ‘#app’,
data() {
return { a: 1 }
}
});

// vm.KaTeX parse error: Expected '}', got 'EOF' at end of input: …console.log(vm.el.innerHTML)// })// 是将内容维护到一个数组里,最终按照顺序顺序。 第一次会开启一个异步任务

vm.a = ‘test’; // 修改了数据后并不会马上更新视图
vm.KaTeX parse error: Expected '}', got 'EOF' at end of input: …console.log(vm.el.innerHTML)
})

// nextTick中的方法会被放到 更新页面watcher的后面去


相关代码如下





![](https://img-blog.csdnimg.cn/img_convert/cda56706ab6045a29f0241299a7ebc6f.webp?x-oss-process=image/format,png)




// src/core/utils/nextTicklet callbacks = [];
let pending = false;
functionflushCallbacks() {
pending = false; //把标志还原为false// 依次执行回调for (let i = 0; i < callbacks.length; i++) {
callbacksi;
}
}
let timerFunc; //定义异步方法 采用优雅降级if (typeofPromise !== “undefined”) {
// 如果支持promiseconst p = Promise.resolve();
timerFunc = () => {
p.then(flushCallbacks);
};
} elseif (typeofMutationObserver !== “undefined”) {
// MutationObserver 主要是监听dom变化 也是一个异步方法let counter = 1;
const observer = newMutationObserver(flushCallbacks);
const textNode = document.createTextNode(String(counter));
observer.observe(textNode, {
characterData: true,
});
timerFunc = () => {
counter = (counter + 1) % 2;
textNode.data = String(counter);
};
} elseif (typeof setImmediate !== “undefined”) {
// 如果前面都不支持 判断setImmediate
timerFunc = () => {
setImmediate(flushCallbacks);
};
} else {
// 最后降级采用setTimeout
timerFunc = () => {
setTimeout(flushCallbacks, 0);
};
}

exportfunctionnextTick(cb) {
// 除了渲染watcher 还有用户自己手动调用的nextTick 一起被收集到数组
callbacks.push(cb);
if (!pending) {
// 如果多次调用nextTick 只会执行一次异步 等异步队列清空之后再把标志变为false
pending = true;
timerFunc();
}
}


数据更新的时候内部会调用nextTick



// src/core/observer/scheduler.jsexportfunctionqueueWatcher (watcher: Watcher) {
const id = watcher.idif (has[id] == null) {
has[id] = trueif (!flushing) {
queue.push(watcher)
} else {
// if already flushing, splice the watcher based on its id// if already past its id, it will be run next immediately.let i = queue.length - 1while (i > index && queue[i].id > watcher.id) {
i–
}
queue.splice(i + 1, 0, watcher)
}
// queue the flushif (!waiting) {
waiting = trueif (process.env.NODE_ENV !== ‘production’ && !config.async) {
flushSchedulerQueue()
return
}
// 把更新方法放到数组中维护[nextTick回调函数,更新函数flushSchedulerQueue]/**
* vm.a = ‘test’; // 修改了数据后并不会马上更新视图
vm.KaTeX parse error: Expected '}', got 'EOF' at end of input: …console.log(vm.el.innerHTML)
})
*/nextTick(flushSchedulerQueue)
}
}
}


#### 那vue中是如何检测数组变化的呢?


数组就是使用 object.defineProperty 重新定义数组的每一项,那能引起数组变化的方法我们都是知道的, pop 、 push 、 shift 、 unshift 、 splice 、 sort 、 reverse 这七种,只要这些方法执行改了数组内容,我就更新内容就好了,是不是很好理解。


1. 是用来函数劫持的方式,重写了数组方法,具体呢就是更改了数组的原型,更改成自己的,用户调数组的一些方法的时候,走的就是自己的方法,然后通知视图去更新。


2. 数组里每一项可能是对象,那么我就是会对数组的每一项进行观测,(且只有数组里的对象才能进行观测,观测过的也不会进行观测)


vue3:改用 proxy ,可直接监听对象数组的变化。


#### 如何从真实DOM到虚拟DOM


涉及到Vue中的模板编译原理,主要过程:


1. 将模板转换成 ast 树, ast 用对象来描述真实的JS语法(将真实DOM转换成虚拟DOM)


2. 优化树


3. 将 ast 树生成代码


#### 虚拟DOM实现原理?


* 虚拟DOM本质上是JavaScript对象,是对真实DOM的抽象


* 状态变更时,记录新树和旧树的差异


* 最后把差异更新到真正的dom中


参考 


## 大厂面试题分享 面试题库


#### 前后端面试题库 (面试必备) 推荐:★★★★★


地址:[前端面试题库](https://bbs.csdn.net/topics/618166371)


#### 为什么Vue采用异步渲染呢?


Vue 是组件级更新,如果不采用异步更新,那么每次更新数据都会对当前组件进行重新渲染,所以为了性能, Vue 会在本轮数据更新后,在异步更新视图。核心思想 nextTick 。


dep.notify() 通知 watcher进行更新, subs[i].update 依次调用 watcher 的 update , queueWatcher 将watcher 去重放入队列, nextTick( flushSchedulerQueue )在下一tick中刷新watcher队列(异步)。


#### Vue3.0 和 2.0 的响应式原理区别


Vue3.x 改用 Proxy 替代 Object.defineProperty。因为 Proxy 可以直接监听对象和数组的变化,并且有多达 13 种拦截方法。


相关代码如下



import { mutableHandlers } from"./baseHandlers"; // 代理相关逻辑import { isObject } from"./util"; // 工具方法exportfunctionreactive(target) {
// 根据不同参数创建不同响应式对象returncreateReactiveObject(target, mutableHandlers);
}
functioncreateReactiveObject(target, baseHandler) {
if (!isObject(target)) {
return target;
}
const observed = newProxy(target, baseHandler);
return observed;
}

const get = createGetter();
const set = createSetter();

functioncreateGetter() {
returnfunctionget(target, key, receiver) {
// 对获取的值进行放射const res = Reflect.get(target, key, receiver);
console.log(“属性获取”, key);
if (isObject(res)) {
// 如果获取的值是对象类型,则返回当前对象的代理对象returnreactive(res);
}
return res;
};
}
functioncreateSetter() {
returnfunctionset(target, key, value, receiver) {
const oldValue = target[key];
const hadKey = hasOwn(target, key);
const result = Reflect.set(target, key, value, receiver);
if (!hadKey) {
console.log(“属性新增”, key, value);
} elseif (hasChanged(value, oldValue)) {
console.log(“属性值被修改”, key, value);
}
return result;
};
}
exportconst mutableHandlers = {
get, // 当获取属性时调用此方法
set, // 当修改属性时调用此方法
};


#### Vue 的生命周期方法有哪些 一般在哪一步发请求


beforeCreate 在实例初始化之后,数据观测(data observer) 和 event/watcher 事件配置之前被调用。在当前阶段 data、methods、computed 以及 watch 上的数据和方法都不能被访问


created 实例已经创建完成之后被调用。在这一步,实例已完成以下的配置:数据观测(data observer),属性和方法的运算, watch/event 事件回调。这里没有��,如果非要想与���进行交互,可以通过��.el,如果非要想与Dom进行交互,可以通过vm.nextTick 来访问 Dom


beforeMount 在挂载开始之前被调用:相关的 render 函数首次被调用。


mounted 在挂载完成后发生,在当前阶段,真实的 Dom 挂载完毕,数据完成双向绑定,可以访问到 Dom 节点


beforeUpdate 数据更新时调用,发生在虚拟 DOM 重新渲染和打补丁(patch)之前。可以在这个钩子中进一步地更改状态,这不会触发附加的重渲染过程


updated 发生在更新完成之后,当前阶段组件 Dom 已完成更新。要注意的是避免在此期间更改数据,因为这可能会导致无限循环的更新,该钩子在服务器端渲染期间不被调用。


beforeDestroy 实例销毁之前调用。在这一步,实例仍然完全可用。我们可以在这时进行善后收尾工作,比如清除计时器。


destroyed Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。 该钩子在服务器端渲染期间不被调用。


activated keep-alive 专属,组件被激活时调用


deactivated keep-alive 专属,组件被销毁时调用



> 
>  异步请求在哪一步发起? 
>  


可以在钩子函数 created、beforeMount、mounted 中进行异步请求,因为在这三个钩子函数中,data 已经创建,可以将服务端端返回的数据进行赋值。


如果异步请求不需要依赖 Dom 推荐在 created 钩子函数中调用异步请求,因为在 created 钩子函数中调用异步请求有以下优点:


* 能更快获取到服务端数据,减少页面 loading 时间;


* ssr 不支持 beforeMount 、mounted 钩子函数,所以放在 created 中有助于一致性;


#### Vue-router 路由有哪些模式?


一般有两种模式: (1)hash 模式:后面的 hash 值的变化,浏览器既不会向服务器发出请求,浏览器也不会刷新,每次 hash 值的变化会触发 hashchange 事件。 (2)history 模式:利用了 HTML5 中新增的 pushState() 和 replaceState() 方法。这两个方法应用于浏览器的历史记录栈,在当前已有的 back、forward、go 的基础之上,它们提供了对历史记录进行修改的功能。只是当它们执行修改时,虽然改变了当前的 URL,但浏览器不会立即向后端发送请求。


#### 虚拟 DOM 的优缺点?


优点:


* 保证性能下限: 框架的虚拟 DOM 需要适配任何上层 API 可能产生的操作,它的一些 DOM 操作的实现必须是普适的,所以它的性能并不是最优的;但是比起粗暴的 DOM 操作性能要好很多,因此框架的虚拟 DOM 至少可以保证在你不需要手动优化的情况下,依然可以提供还不错的性能,即保证性能的下限;


* 无需手动操作 DOM: 我们不再需要手动去操作 DOM,只需要写好 View-Model 的代码逻辑,框架会根据虚拟 DOM 和 数据双向绑定,帮我们以可预期的方式更新视图,极大提高我们的开发效率;


* 跨平台: 虚拟 DOM 本质上是 JavaScript 对象,而 DOM 与平台强相关,相比之下虚拟 DOM 可以进行更方便地跨平台操作,例如服务器渲染、weex 开发等等。


缺点:


* 无法进行极致优化: 虽然虚拟 DOM + 合理的优化,足以应对绝大部分应用的性能需求,但在一些性能要求极高的应用中虚拟 DOM 无法进行针对性的极致优化。


#### vue和react的区别


=> 相同点:



  1. 数据驱动页面,提供响应式的试图组件
  2. 都有virtual DOM,组件化的开发,通过props参数进行父子之间组件传递数据,都实现了webComponents规范
  3. 数据流动单向,都支持服务器的渲染SSR
  4. 都有支持native的方法,react有React native, vue有wexx

=> 不同点:



1.数据绑定:Vue实现了双向的数据绑定,react数据流动是单向的
2.数据渲染:大规模的数据渲染,react更快
3.使用场景:React配合Redux架构适合大规模多人协作复杂项目,Vue适合小快的项目
4.开发风格:react推荐做法jsx + inline style把html和css都写在js了
vue是采用webpack + vue-loader单文件组件格式,html, js, css同一个文件


#### v-model 的原理?


我们在 vue 项目中主要使用 v-model 指令在表单 input、textarea、select 等元素上创建双向数据绑定,我们知道 v-model 本质上不过是语法糖,v-model 在内部为不同的输入元素使用不同的属性并抛出不同的事件:


* text 和 textarea 元素使用 value 属性和 input 事件;


* checkbox 和 radio 使用 checked 属性和 change 事件;


* select 字段将 value 作为 prop 并将 change 作为事件。


以 input 表单元素为例:



相当于


如果在自定义组件中,v-model 默认会利用名为 value 的 prop 和名为 input 的事件,如下所示:



父组件:

文末

如果30岁以前,可以还不知道自己想去做什么的话,那30岁之后,真的觉得时间非常的宝贵,不能再浪费时间在一些碎片化的事情上,比如说看综艺,电视剧。一个人的黄金时间也就二,三十年,不能过得浑浑噩噩。所以花了基本上休息的时间,去不断的完善自己的知识体系,希望可以成为一个领域内的TOP。

同样是干到30岁,普通人写业务代码划水,榜样们深度学习拓宽视野晋升管理。

这也是为什么大家都说30岁是程序员的门槛,很多人迈不过去,其实各行各业都是这样都会有个坎,公司永远都缺的高级人才,只用这样才能在大风大浪过后,依然闪耀不被公司淘汰不被社会淘汰。

269页《前端大厂面试宝典》

包含了腾讯、字节跳动、小米、阿里、滴滴、美团、58、拼多多、360、新浪、搜狐等一线互联网公司面试被问到的题目,涵盖了初中级前端技术点。

开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】

前端面试题汇总

JavaScript

  • 17
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值