中等难度Vue 面试题+详解答案

//需要做依赖收集过程 这里代码没写出来

return value;

},

set(newValue) {

if (newValue === value) return;

console.log(“设置值”);

//需要做派发更新过程 这里代码没写出来

value = newValue;

},

});

}

export function observe(value) {

// 如果传过来的是对象或者数组 进行属性劫持

if (

Object.prototype.toString.call(value) === “[object Object]” ||

Array.isArray(value)

) {

return new Observer(value);

}

}

2 Vue 如何检测数组变化

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

所以在 Vue 中修改数组的索引和长度是无法监控到的。需要通过以上 7 种变异方法修改数组才会触发数组对应的 watcher 进行更新

相关代码如下

// src/obserber/array.js

// 先保留数组原型

const arrayProto = Array.prototype;

// 然后将arrayMethods继承自数组原型

// 这里是面向切片编程思想(AOP)–不破坏封装的前提下,动态的扩展功能

export const arrayMethods = Object.create(arrayProto);

let methodsToPatch = [

“push”,

“pop”,

“shift”,

“unshift”,

“splice”,

“reverse”,

“sort”,

];

methodsToPatch.forEach((method) => {

arrayMethods[method] = function (…args) {

// 这里保留原型方法的执行结果

const result = arrayProto[method].apply(this, args);

// 这句话是关键

// this代表的就是数据本身 比如数据是{a:[1,2,3]} 那么我们使用a.push(4) this就是a ob就是a.ob 这个属性就是上段代码增加的 代表的是该数据已经被响应式观察过了指向Observer实例

const ob = this.ob;

// 这里的标志就是代表数组有新增操作

let inserted;

switch (method) {

case “push”:

case “unshift”:

inserted = args;

break;

case “splice”:

inserted = args.slice(2);

default:

break;

}

// 如果有新增的元素 inserted是一个数组 调用Observer实例的observeArray对数组每一项进行观测

if (inserted) ob.observeArray(inserted);

// 之后咱们还可以在这里检测到数组改变了之后从而触发视图更新的操作–后续源码会揭晓

return result;

};

});

3 vue3.0 用过吗 了解多少
  • 响应式原理的改变 Vue3.x 使用 Proxy 取代 Vue2.x 版本的 Object.defineProperty

  • 组件选项声明方式 Vue3.x 使用 Composition API setup 是 Vue3.x 新增的一个选项, 他是组件内使用 Composition API 的入口。

  • 模板语法变化 slot 具名插槽语法 自定义指令 v-model 升级

  • 其它方面的更改 Suspense 支持 Fragment(多个根节点)和 Protal(在 dom 其他部分渲染组建内容)组件,针对一些特殊的场景做了处理。 基于 treeshaking 优化,提供了更多的内置功能。

Vue3.0 新特性以及使用经验总结 传送门

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

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

相关代码如下

import { mutableHandlers } from “./baseHandlers”; // 代理相关逻辑

import { isObject } from “./util”; // 工具方法

export function reactive(target) {

// 根据不同参数创建不同响应式对象

return createReactiveObject(target, mutableHandlers);

}

function createReactiveObject(target, baseHandler) {

if (!isObject(target)) {

return target;

}

const observed = new Proxy(target, baseHandler);

return observed;

}

const get = createGetter();

const set = createSetter();

function createGetter() {

return function get(target, key, receiver) {

// 对获取的值进行放射

const res = Reflect.get(target, key, receiver);

console.log(“属性获取”, key);

if (isObject(res)) {

// 如果获取的值是对象类型,则返回当前对象的代理对象

return reactive(res);

}

return res;

};

}

function createSetter() {

return function set(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);

} else if (hasChanged(value, oldValue)) {

console.log(“属性值被修改”, key, value);

}

return result;

};

}

export const mutableHandlers = {

get, // 当获取属性时调用此方法

set, // 当修改属性时调用此方法

};

5 Vue 的父子组件生命周期钩子函数执行顺序
  • 加载渲染过程

父 beforeCreate->父 created->父 beforeMount->子 beforeCreate->子 created->子 beforeMount->子 mounted->父 mounted

  • 子组件更新过程

父 beforeUpdate->子 beforeUpdate->子 updated->父 updated

  • 父组件更新过程

父 beforeUpdate->父 updated

  • 销毁过程

父 beforeDestroy->子 beforeDestroy->子 destroyed->父 destroyed

6 虚拟 DOM 是什么 有什么优缺点

由于在浏览器中操作 DOM 是很昂贵的。频繁的操作 DOM,会产生一定的性能问题。这就是虚拟 Dom 的产生原因。Vue2 的 Virtual DOM 借鉴了开源库 snabbdom 的实现。Virtual DOM 本质就是用一个原生的 JS 对象去描述一个 DOM 节点,是对真实 DOM 的一层抽象。

优点:

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

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

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

缺点:

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

  2. 首次渲染大量 DOM 时,由于多了一层虚拟 DOM 的计算,会比 innerHTML 插入慢。

7 v-model 原理

v-model 只是语法糖而已

v-model 在内部为不同的输入元素使用不同的 property 并抛出不同的事件:

  • text 和 textarea 元素使用 value property 和 input 事件;

  • checkbox 和 radio 使用 checked property 和 change 事件;

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

注意:对于需要使用输入法 (如中文、日文、韩文等) 的语言,你会发现 v-model 不会在输入法组合文字过程中得到更新。

在普通标签上

//这一行等于下一行

在组件上

Vue.component(‘currency-input’, {

template: `

<input

ref=“input”

:value=“value”

@input=“$emit(‘input’, $event.target.value)”

`,

props: [‘value’],

})

8 v-for 为什么要加 key

如果不使用 key,Vue 会使用一种最大限度减少动态元素并且尽可能的尝试就地修改/复用相同类型元素的算法。key 是为 Vue 中 vnode 的唯一标记,通过这个 key,我们的 diff 操作可以更准确、更快速

更准确:因为带 key 就不是就地复用了,在 sameNode 函数 a.key === b.key 对比中可以避免就地复用的情况。所以会更加准确。

更快速:利用 key 的唯一性生成 map 对象来获取对应节点,比遍历方式更快

相关代码如下

// 判断两个vnode的标签和key是否相同 如果相同 就可以认为是同一节点就地复用

function isSameVnode(oldVnode, newVnode) {

return oldVnode.tag === newVnode.tag && oldVnode.key === newVnode.key;

}

// 根据key来创建老的儿子的index映射表 类似 {‘a’:0,‘b’:1} 代表key为’a’的节点在第一个位置 key为’b’的节点在第二个位置

function makeIndexByKey(children) {

let map = {};

children.forEach((item, index) => {

map[item.key] = index;

});

return map;

}

// 生成的映射表

let map = makeIndexByKey(oldCh);

9 Vue 事件绑定原理

原生事件绑定是通过 addEventListener 绑定给真实元素的,组件事件绑定是通过 Vue 自定义的$on 实现的。如果要在组件上使用原生事件,需要加.native 修饰符,这样就相当于在父组件中把子组件当做普通 html 标签,然后加上原生事件。

o n 、 on、 on、emit 是基于发布订阅模式的,维护一个事件中心,on 的时候将事件按名称存在事件中心里,称之为订阅者,然后 emit 将对应的事件进行发布,去执行事件中心里的对应的监听器

10 vue-router 路由钩子函数是什么 执行顺序是什么

路由钩子的执行流程, 钩子函数种类有:全局守卫、路由守卫、组件守卫

完整的导航解析流程:

  1. 导航被触发。

  2. 在失活的组件里调用 beforeRouteLeave 守卫。

  3. 调用全局的 beforeEach 守卫。

  4. 在重用的组件里调用 beforeRouteUpdate 守卫 (2.2+)。

  5. 在路由配置里调用 beforeEnter。

  6. 解析异步路由组件。

  7. 在被激活的组件里调用 beforeRouteEnter。

  8. 调用全局的 beforeResolve 守卫 (2.5+)。

  9. 导航被确认。

  10. 调用全局的 afterEach 钩子。

  11. 触发 DOM 更新。

  12. 调用 beforeRouteEnter 守卫中传给 next 的回调函数,创建好的组件实例会作为回调函数的参数传入。

11 vue-router 动态路由是什么 有什么问题

我们经常需要把某种模式匹配到的所有路由,全都映射到同个组件。例如,我们有一个 User 组件,对于所有 ID 各不相同的用户,都要使用这个组件来渲染。那么,我们可以在 vue-router 的路由路径中使用“动态路径参数”(dynamic segment) 来达到这个效果:

const User = {

template: “

User
”,

};

const router = new VueRouter({

routes: [

// 动态路径参数 以冒号开头

{ path: “/user/:id”, component: User },

],

});

问题:vue-router 组件复用导致路由参数失效怎么办?

解决方法:

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:前端)

最后

分享一套阿里大牛整理的前端资料给大家,点击前端校招面试题精编解析大全即可免费下载

❤️ 谢谢支持,喜欢的话别忘了 关注、点赞哦。

摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!**

因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

[外链图片转存中…(img-Aeodn5LO-1713641018199)]

[外链图片转存中…(img-2L36Oo1y-1713641018200)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!

[外链图片转存中…(img-bitERvgo-1713641018201)]

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:前端)

[外链图片转存中…(img-JuPPFdFT-1713641018201)]

最后

分享一套阿里大牛整理的前端资料给大家,点击前端校招面试题精编解析大全即可免费下载

❤️ 谢谢支持,喜欢的话别忘了 关注、点赞哦。

前端校招面试题精编解析大全

  • 24
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值