网易首页 > 网易号 > 正文 申请入驻

前端培训:Vue 面试题分享

0
分享至

1.请说一下响应式数据的理解?

核心答案:

数组和对象类型当值变化时如何劫持到。对象内部通过defineReactive方法,使用Object.defineProperty将属性进行劫持(只会劫持已经存在的属性),数组则是通过重写数组方法来实现。

这里在回答时可以带出一些相关知识点(比如多层对象是通过递归来实现劫持,顺带提出Vue3中是使用proxy来实现响应式数据)

补充回答:

内部依赖收集是怎样做到的,每个属性都拥有自己的dep属性,存放他所依赖的watcher,当属性变化后会通知自己对应的watcher去更新 (其实后面会讲到每个对象类型自己本身也拥有一个dep属性,这个在$set面试题中在进行讲解)

这里可以引出性能优化相关的内容 (1)对象层级过深,性能就会差 (2)不需要响应数据的内容不要放到data中 (3) Object.freeze() 可以冻结数据

快速Mock:

let state = { count: 0 };

// app.innerHTML = state.count;

// 1.将数据变成响应式数据

let active;

function defineReactive(obj) {

for (let key in obj) {

let value = obj[key];

let dep = [];

Object.defineProperty(obj, key, {

get() {

if (active) {

dep.push(active);

return value;

},

set(newValue) {

value = newValue;

dep.forEach(fn => fn());

defineReactive(state);

const watcher = (fn) => {

active = fn;

fn();

active = null;

watcher(() => {

app.innerHTML = state.count;

watcher(() => {

console.log(state.count)

2.Vue如何检测数组变化?

核心答案:

数组考虑性能原因没有用defineProperty对数组的每一项进行拦截,而是选择重写数组(push,shift,pop,splice,unshift,sort,reverse)方法进行重写。

补充回答:

在Vue中修改数组的索引和长度是无法监控到的。需要通过以上7种变异方法修改数组才会触发数组对应的watcher进行更新。数组中如果是对象数据类型也会进行递归劫持。

那如果想更改索引更新数据怎么办?可以通过Vue.$set()来进行处理 =》 核心内部用的是splice方法

快速Mock:

let state = [1,2,3];

let originArray = Array.prototype;

let arrayMethods = Object.create(originArray);

function defineReactive(obj) {

arrayMethods.push = function (...args) {

originArray.push.call(this,...args);

render();

obj.__proto__ = arrayMethods;

defineReactive(state);

function render(){

app.innerHTML = state;

render();

state.push(4);

3.Vue中模板编译原理?

核心答案:

如何将template转换成render函数(这里要注意的是我们在开发时尽量不要使用template,因为将template转化成render方法需要在运行时进行编译操作会有性能损耗,同时引用带有compiler包的vue体积也会变大。默认.vue文件中的template处理是通过vue-loader来进行处理的并不是通过运行时的编译 - 后面我们会说到默认vue项目中引入的vue.js是不带有compiler模块的)。

  • 1.将template模板转换成ast语法树 - parserHTML
  • 2.对静态语法做静态标记 - markUp
  • 3.重新生成代码 -codeGen

补充回答:

模板引擎的实现原理就是new Function + with来进行实现的

vue-loader中处理template属性主要靠的是vue-template-compiler模块

快速Mock:

let { ast, render } = VueTemplateCompiler.compile('

hello world

console.log(ast, render);

const fn = new Function(render);

console.log(fn.toString());

4.生命周期钩子是如何实现的?

核心答案:

Vue的生命周期钩子就是回调函数而已,当创建组件实例的过程中会调用对应的钩子方法

补充回答:

内部主要是使用callHook方法来调用对应的方法。核心是一个发布订阅模式,将钩子订阅好(内部采用数组的方式存储),在对应的阶段进行发布!

快速Mock:

function mergeHook(parentVal, childValue) {

if (childValue) {

if (parentVal) {

return parentVal.concat(childValue);

} else {

return [childValue]

} else {

return parentVal;

function mergeOptions(parent, child) {

let opts = {};

for (let key in child) {

opts[key] = mergeHook(parent[key], child[key]);

return opts;

function callHook(vm, key) {

vm.options[key].forEach(hook => hook());

function Vue(options) {

this.options = mergeOptions(this.constructor.options, options);

callHook(this, 'beforeCreate');

Vue.options = {}

new Vue({

beforeCreate() {

console.log('before create')

5.Vue.mixin的使用场景和原理?

核心答案:

Vue.mixin的作用就是抽离公共的业务逻辑,原理类似“对象的继承”,当组件初始化时会调用mergeOptions方法进行合并,采用策略模式针对不同的属性进行合并。如果混入的数据和本身组件中的数据冲突,会采用“就近原则”以组件的数据为准。

补充回答:

mixin中有很多缺陷 "命名冲突问题"、"依赖问题"、"数据来源问题",这里强调一下mixin的数据是不会被共享的!

快速Mock:

Vue.mixin = function (obj) {

this.options = mergeOptions(this.options,obj);

Vue.mixin({

beforeCreate(){

console.log('before create ok')

6.nextTick在哪里使用?原理是?

核心答案:

nextTick中的回调是在下次 DOM 更新循环结束之后执行的延迟回调。【关注尚硅谷,轻松学IT】在修改数据之后立即使用这个方法,获取更新后的 DOM。原理就是异步方法(promise,mutationObserver,setImmediate,setTimeout)经常与事件环一起来问(宏任务和微任务)

补充回答:

vue多次更新数据,最终会进行批处理更新。内部调用的就是nextTick实现了延迟更新,用户自定义的nextTick中的回调会被延迟到更新完成后调用,从而可以获取更新后的DOM。

快速Mock:

let cbs = [];

let pending = false;

function flushCallbacks() {

cbs.forEach(fn=>fn());

function nextTick(fn) {

cbs.push(fn);

if (!pending) {

pending = true;

setTimeout(() => {

flushCallbacks();

}, 0);

function render() {

console.log('rerender');

nextTick(render)

nextTick(render)

nextTick(render);

console.log('sync...')

7.Vue为什么需要虚拟DOM?

核心答案:

Virtual DOM就是用js对象来描述真实DOM,是对真实DOM的抽象,由于直接操作DOM性能低但是js层的操作效率高,可以将DOM操作转化成对象操作,最终通过diff算法比对差异进行更新DOM(减少了对真实DOM的操作)。虚拟DOM不依赖真实平台环境从而也可以实现跨平台。

补充回答:

虚拟DOM的实现就是普通对象包含tag、data、children等属性对真实节点的描述。(本质上就是在JS和DOM之间的一个缓存)

8.Vue中的diff原理

核心答案:

Vue的diff算法是平级比较,不考虑跨级比较的情况。内部采用深度递归的方式 + 双指针的方式进行比较。

补充回答:

  • 1.先比较是否是相同节点
  • 2.相同节点比较属性,并复用老节点
  • 3.比较儿子节点,考虑老节点和新节点儿子的情况
  • 4.优化比较:头头、尾尾、头尾、尾头
  • 5.比对查找进行复用

Vue3中采用最长递增子序列实现diff算法

9.Vue.set方法是如何实现的?

核心答案:

为什么$set可以触发更新,我们给对象和数组本身都增加了dep属性。当给对象新增不存在的属性则触发对象依赖的watcher去更新,当修改数组索引时我们调用数组本身的splice方法去更新数组

export function set (target: Array | Object, key: any, val: any): any {

// 1.是开发环境 target 没定义或者是基础类型则报错

if (process.env.NODE_ENV !== 'production' &&

(isUndef(target) || isPrimitive(target))

warn(`Cannot set reactive property on undefined, null, or primitive value: ${(target: any)}`)

// 2.如果是数组 Vue.set(array,1,100); 调用我们重写的splice方法 (这样可以更新视图)

if (Array.isArray(target) && isValidArrayIndex(key)) {

target.length = Math.max(target.length, key)

target.splice(key, 1, val)

return val

// 3.如果是对象本身的属性,则直接添加即可

if (key in target && !(key in Object.prototype)) {

target[key] = val

return val

const ob = (target: any).__ob__

// 4.如果是Vue实例 或 根数据data时 报错

if (target._isVue || (ob && ob.vmCount)) {

process.env.NODE_ENV !== 'production' && warn(

'Avoid adding reactive properties to a Vue instance or its root $data ' +

'at runtime - declare it upfront in the data option.'

return val

// 5.如果不是响应式的也不需要将其定义成响应式属性

if (!ob) {

target[key] = val

return val

// 6.将属性定义成响应式的

defineReactive(ob.value, key, val)

// 7.通知视图更新

ob.dep.notify()

return val

10.Vue的生命周期方法有哪些?一般在哪一步发起请求及原因

核心答案:

  • beforeCreate 在实例初始化之后,数据观测(data observer) 和 event/watcher 事件配置之前被调用。
  • created 实例已经创建完成之后被调用。在这一步,实例已完成以下的配置:数据观测(data observer),属性和方法的运算, watch/event 事件回调。这里没有$el
  • beforeMount 在挂载开始之前被调用:相关的 render 函数首次被调用。
  • mounted el 被新创建的 vm.$el 替换,并挂载到实例上去之后调用该钩子。
  • beforeUpdate 数据更新时调用,发生在虚拟 DOM 重新渲染和打补丁之前。
  • updated 由于数据更改导致的虚拟 DOM 重新渲染和打补丁,在这之后会调用该钩子。
  • beforeDestroy 实例销毁之前调用。在这一步,实例仍然完全可用。
  • destroyed Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。该钩子在服务器端渲染期间不被调用。

补充回答:

  • created 实例已经创建完成,因为它是最早触发的原因可以进行一些数据,资源的请求。(服务端渲染支持created方法)
  • mounted 实例已经挂载完成,可以进行一些DOM操作
  • beforeUpdate 可以在这个钩子中进一步地更改状态,这不会触发附加的重渲染过程。
  • updated 可以执行依赖于 DOM 的操作。然而在大多数情况下,你应该避免在此期间更改状态,因为这可能会导致更新无限循环。该钩子在服务器端渲染期间不被调用。
  • destroyed 可以执行一些优化操作,清空定时器,解除绑定事件

11.Vue组件间传值的方式及之间的区别?

  • props和父组件向子组件传递数据是通过传递的,子组件传递数据给父组件是通过emit触发事件来做到的
  • children 获取当前组件的父组件和当前组件的子组件
  • $attrs和$listeners A->B->C。Vue 2.4 开始提供了$attrs和$listeners来解决这个问题
  • 父组件中通过provide来提供变量,然后在子组件中通过inject来注入变量。
  • $refs 获取实例
  • envetBus 平级组件数据传递 这种情况下可以使用中央事件总线的方式
  • vuex状态管理

(1) props实现:src/core/vdom/create-component.js:101、 src/core/instance/init.js:74、scr/core/instance/state:64

(2) 事件机制实现: src/core/vdom/create-component.js:101、 src/core/instance/init.js:74、src/core/instance/events.js:12

(3) parent&children实现:src/core/vdom/create-component.js:47、src/core/instance/lifecycle.js:32

(4) provide&inject实现: src/core/instance/inject.js:7

(5) $attrs&$listener: src/core/instance/render.js:49、src/core/instance/lifecycle.js:215

(6) $rsrc/core/vdom/modules/reg.js:20

12.$attrs是为了解决什么问题出现的?应用场景有哪些?provide/inject 不能解决它能解决的问题吗?

核心答案:

$attrs主要的作用就是实现批量传递数据。provide/inject更适合应用在插件中,主要是实现跨级数据传递

13.Vue的组件渲染流程?

核心答案:

1. 父子组件渲染的先后顺序

2. 组件是如何渲染到页面上的

①在渲染父组件时会创建父组件的虚拟节点,其中可能包含子组件的标签

②在创建虚拟节点时,获取组件的定义使用Vue.extend生成组件的构造函数。

③将虚拟节点转化成真实节点时,会创建组件的实例并且调用组件的$mount方法。

④所以组件的创建过程是先父后子

14.Vue中组件的data为什么是一个函数?

核心答案:

每次使用组件时都会对组件进行实例化操作,并且调用data函数返回一个对象作为组件的数据源。这样可以保证多个组件间数据互不影响

快速Mock:

class Vue{

constructor(options){

this.data = options.data();

let data = ()=>({a:1})

let d1 = new Vue({data});

let d2 = new Vue({data});

d1.data.a = 100;

console.log(d2); // 1

15.请说下v-if和v-show的区别

核心答案:

v-if在编译过程中会被转化成三元表达式,条件不满足时不渲染此节点。v-show会被编译成指令,条件不满足时控制样式将对应节点隐藏 (内部其他指令依旧会继续执行)

扩展回答: 频繁控制显示隐藏尽量不使用v-if,v-if和v-for尽量不要连用

v-if源码剖析:

function genIfConditions (

conditions: ASTIfConditions,

state: CodegenState,

altGen?: Function,

altEmpty?: string

): string {

if (!conditions.length) {

return altEmpty || '_e()'

const condition = conditions.shift()

if (condition.exp) { // 如果有表达式

return `(${condition.exp})?${ // 将表达式作为条件拼接成元素

genTernaryExp(condition.block)

genIfConditions(conditions, state, altGen, altEmpty)

} else {

return `${genTernaryExp(condition.block)}` // 没有表达式直接生成元素 像v-else

// v-if with v-once should generate code like (a)?_m(0):_m(1)

function genTernaryExp (el) {

return altGen

? altGen(el, state)

: el.once

? genOnce(el, state)

: genElement(el, state)

v-show源码剖析:

bind (el: any, { value }: VNodeDirective, vnode: VNodeWithData) {

const originalDisplay = el.__vOriginalDisplay =

el.style.display === 'none' ? '' : el.style.display // 获取原始显示值

el.style.display = value ? originalDisplay : 'none' // 根据属性控制显示或者隐藏

文章来源:前端大全

特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相关推荐
热点推荐
神级躺赢!索汉提前锁定NBA总冠军戒指 本季先后效力马刺尼克斯

神级躺赢!索汉提前锁定NBA总冠军戒指 本季先后效力马刺尼克斯

醉卧浮生
2026-06-01 05:45:13
天空:拉什福德正在迈阿密国际训练基地训练,这里设施顶尖

天空:拉什福德正在迈阿密国际训练基地训练,这里设施顶尖

懂球帝
2026-06-01 23:45:07
亏光1亿后67亿“卖掉”公司,小杨哥这次能成功翻身吗?

亏光1亿后67亿“卖掉”公司,小杨哥这次能成功翻身吗?

青眼财经
2026-06-01 10:37:30
2026,人类第一次面对“高温围城”:这一次,谁先撑不住?

2026,人类第一次面对“高温围城”:这一次,谁先撑不住?

李砍柴
2026-06-01 16:18:39
演员王星军:与关牧村离婚34年,65岁未再婚,他到底追求什么?

演员王星军:与关牧村离婚34年,65岁未再婚,他到底追求什么?

飘飘然的娱乐汇
2026-06-01 19:15:05
中央明确了!社保最低缴费年限要提高,70、80后得早做准备

中央明确了!社保最低缴费年限要提高,70、80后得早做准备

云鹏叙事
2026-04-12 16:36:39
洛夫顿又回上海了!球迷偶遇独自一人吃外卖,估计是治疗去的?

洛夫顿又回上海了!球迷偶遇独自一人吃外卖,估计是治疗去的?

篮球资讯达人
2026-06-01 20:27:06
中际旭创,成沪深300指数第一大权重股

中际旭创,成沪深300指数第一大权重股

证券时报
2026-06-01 22:51:04
1996年,他与董建华竞选特首失败,没想到,却成了香港头号包租公

1996年,他与董建华竞选特首失败,没想到,却成了香港头号包租公

鉴史录
2026-06-01 12:59:01
38天首球!1.5亿欧巨星复活:40米奔袭一条龙破门 绝美弧线太霸道

38天首球!1.5亿欧巨星复活:40米奔袭一条龙破门 绝美弧线太霸道

风过乡
2026-06-02 06:10:00
石家庄市第十五届人民代表大会常务委员会公告

石家庄市第十五届人民代表大会常务委员会公告

环球网资讯
2026-06-01 22:19:05
足坛一夜动态:挪威击败瑞典,土耳其4球大胜,奥地利1-0突尼斯

足坛一夜动态:挪威击败瑞典,土耳其4球大胜,奥地利1-0突尼斯

足球狗说
2026-06-02 04:44:59
百万网红边牧被卖后续!母亲崩溃怒斥,当事人放话,收狗人曝内情

百万网红边牧被卖后续!母亲崩溃怒斥,当事人放话,收狗人曝内情

奇思妙想草叶君
2026-05-30 22:22:07
国产新伟哥上市!舌下含服15分钟起效,不伤血管,中老年男性适用

国产新伟哥上市!舌下含服15分钟起效,不伤血管,中老年男性适用

思思夜话
2026-06-01 15:24:26
毛主席派宋时轮给刘志丹当助手,宋吐苦水:我已被开除党籍一年了

毛主席派宋时轮给刘志丹当助手,宋吐苦水:我已被开除党籍一年了

我不是沃神
2026-06-02 08:10:03
苹果眼镜要掀翻两千亿美元眼镜市场?套路跟手表一样

苹果眼镜要掀翻两千亿美元眼镜市场?套路跟手表一样

薛定谔的BUG
2026-06-01 20:16:02
雷霆出局侧证詹皇伟大!美媒晒4点为LBJ写赞歌:八连总决轻松吗?

雷霆出局侧证詹皇伟大!美媒晒4点为LBJ写赞歌:八连总决轻松吗?

颜小白的篮球梦
2026-06-01 23:01:37
32岁白举纲喜为人父,1岁女儿白胖可爱,妻子非圈内人

32岁白举纲喜为人父,1岁女儿白胖可爱,妻子非圈内人

书慧我心
2026-06-01 14:13:33
下个沪电股份?这家11元低价+高端PCB铜箔龙头   主力暴抢16亿元

下个沪电股份?这家11元低价+高端PCB铜箔龙头 主力暴抢16亿元

元芳说投资
2026-06-02 00:00:09
伊劳拉即将执教利物浦 同时获得一个超强辅助!

伊劳拉即将执教利物浦 同时获得一个超强辅助!

小彭美识
2026-06-02 07:47:07
2026-06-02 09:00:49
IT爱好者小尚
IT爱好者小尚
分享IT教育类信息
630文章数 55关注度
往期回顾 全部

科技要闻

英伟达RTX Spark 很猛,但首批机型不便宜

头条要闻

牛弹琴:伊朗突然发飙 特朗普急了被迫打了一个电话

头条要闻

牛弹琴:伊朗突然发飙 特朗普急了被迫打了一个电话

体育要闻

杰威:如果我没受伤,我们能击败马刺

娱乐要闻

奚梦瑶婚礼现场图!一双儿女当花童

财经要闻

宇树过会,杭州赢麻了

汽车要闻

奇瑞集团5月销量24.8万辆 同比增长20.5% 出口18.2万辆再创新高

态度原创

亲子
时尚
旅游
房产
手机

亲子要闻

国家卫生健康委:我国儿童健康水平持续提升……一起来听健康早闻!2026年6月2日

安妮海瑟薇40岁后美出新高度, 开挂的关键原来是这个

旅游要闻

“海南之夜”旅游专场欢迎活动举行 海外旅行商共赴海南之约

房产要闻

100亿!1371亩!海口城市更新,再爆超级项目!

手机要闻

苹果WWDC26下周开幕,新标语“全高光就位”暗指Siri将迎改版

无障碍浏览 进入关怀版