天天看点

前端工程师常见面试题(前端进阶)——Vue 框架

作者:银色灰龙

有使用过 Vue 吗?说说你对 Vue 的理解

参考回答:

Vue 是一个构建数据驱动的渐进性框架,它的目标是通过 API 实现响应数据绑定和视图 更新。

说说 Vue 的优缺点

参考回答:

优点:

1、数据驱动视图,对真实 dom 进行抽象出virtual dom (本质就是一个 js 对象) , 并配合 diff 算法 、响应式和观察者 、异步队列等手段以最小代价更新dom, 渲染 页面

2 、组件化, 组件用单文件的形式进行代码的组织编写, 使得我们可以在一个文 件里编写 html\css (scoped 属性配置 css 隔离) \js 并且配合 Vue-loader 之后, 支 持更强大的预处理器等功能

3 、强大且丰富的 API 提供一系列的 api 能满足业务开发中各类需求

4 、 由于采用虚拟 dom, 让 Vue ssr 先天就足

5 、生命周期钩子函数, 选项式的代码组织方式, 写熟了还是蛮顺畅的, 但仍然 有优化空间 ( Vue3 composition-api)

6 、生态好, 社区活跃 缺点:

(1) 、 由于底层基于 Object.defineProperty 实现响应式, 而这个 api 本身不支持 IE8 及以下浏览器

(2) 、csr 的先天不足, 首屏性能问题 (白屏)

(3)、 由于百度等搜索引擎爬虫无法爬取 js 中的内容, 故 spa 先天就对 seo 优化心 有余力不足 (谷歌的 puppeteer 就挺牛逼的, 实现预渲染底层也是用到了这个工具)

Vue 和 React 有什么不同? 使用场景分别是什么?

参考回答:

1、Vue 是完整一套由官方维护的框架, 核心库主要有由尤雨溪大神独自维护, 而 React 是不要脸的书维护 (很多库由社区维护) ,曾经一段时间很多人质疑 Vue 的后续维护性, 似乎这并不是问题。

2 、Vue 上手简单, 进阶式框架, 白话说你可以学一点, 就可以在你项目中去用一点, 你不一定需要一次性学习整个 Vue 才能去使用它, 而 React, 恐怕如果你这样会面对项 目束手无策。

3、语法上 Vue 并不限制你必须 es6+完全 js 形式编写页面,可以视图和 js 逻辑尽可能分 离, 减少很多人看不惯 React-jsx 的恶心嵌套, 毕竟都是作为前端开发者, 还是更习惯 于 html 干净。

4、很多人说 React 适合大型项目,适合什么什么,Vue 轻量级,适合移动端中小型项目, 其实我想说,说这话的人是心里根本没点逼数,Vue 完全可以应对复杂的大型应用,甚 至于说如果你 React 学的不是很好,写出来的东西或根本不如 Vue 写的,毕竟 Vue 跟着 官方文档撸就行, 自有人帮你规范, 而 React 比较懒散自由, 可以自由发挥

5、Vue 在国内人气明显胜过 React,这很大程度上得益于它的很多语法包括编程思维更 符合国人思想。

什么是虚拟 DOM?

参考回答:

虚拟 dom 是相对于浏览器所渲染出来的真实 dom 的, 在 react, vue 等技术出现之前, 我们要改变页面展示的内容只能通过遍历查询 dom 树的方式找到需要修改的 dom 然 后修改样式行为或者结构, 来达到更新 ui 的目的。

这种方式相当消耗计算资源, 因为每次查询 dom 几乎都需要遍历整颗 dom 树, 如果 建立一个与 dom 树对应的虚拟 dom 对象 ( js 对象) ,以对象嵌套的方式来表示 dom 树,那么每次 dom 的更改就变成了 js 对象的属性的更改,这样一来就能查找 js 对象 的属性变化要比查询 dom 树的性能开销小。

请描述下 vue 的生命周期是什么?

参考回答:

生命周期就是 vue 从开始创建到销毁的过程,分为四大步 (创建,挂载, 更新,销毁) ,每一步又分为两小步,如 beforeCreate,created。beforeCreate 前, 也就是 new Vue 的时候会初始化事件和生命周期;

beforeCreate 和 created 之间会挂载 Data,绑定事件;

接下来会根据 el 挂载页面元素,如 果没有设置 el 则生命周期结束, 直到手动挂载;

el 挂载结束后, 根据 templete/outerHTML(el)渲染页面;

在 beforeMount 前虚拟 DOM 已经创建完成;

之后在 mounted 前,将 vm.$el 替换掉页面元素 el;

mounted 将虚拟 dom 挂载到真实页面 (此时页面已经全部渲染完成) ;

之后发生数据变化时 触发 beforeUpdate 和 updated 进行一些操作;

最后主动调用销毁函数或者 组件自动销毁时 beforeDestroy,手动撤销监听事件,计时器等;

destroyed 时仅存在 Dom 节点, 其他所有东西已自动销毁 。这就是我所理解的vue 的一个完整的生命周期。

前端工程师常见面试题(前端进阶)——Vue 框架

vue 如何监听键盘事件?

参考回答:

1. @keyup. 方法

<template>

<input ref="myInput" type="text" value="hello world" autofocus

@keyup.enter="handleKey">

</template>

<script>

export default {

methods: {

handleKey(e) {

console.log(e)

}

}

}

</script>           

2. addEventListener

<script>

export default {

mounted() {

document.addEventListener('keyup', this.handleKey)

},

beforeDestroy() {

document.removeEventListener('keyup', this.handleKey)

},

methods: {

handleKey(e) {

console.log(e)

}

}

}

</script>

<script>

export default {

mounted() {

document.addEventListener('keyup', this.handleKey)

},

beforeDestroy() {

document.removeEventListener('keyup', this.handleKey)

},

methods: {

handleKey(e) {

console.log(e)

}

}

}

</script>           

watch 怎么深度监听对象变化

参考回答:

deep 设置为true 就可以监听到对象的变化

let vm=new Vue({

el:"#first",

data:{msg:{name:'北京'}},

watch:{

msg:{

handler (newMsg,oldMsg){

console.log(newMsg);

},

immediate:true,

deep:true

}

}

})           

删除数组用 delete 和 Vue.delete 有什么区别?

参考回答:

delete: 只是被删除数组成员变为 empty / undefined, 其他元素键值不变 Vue.delete: 直接删了数组成员, 并改变了数组的键值 (对象是响应式的, 确保

删除能触发更新视图,这个方法主要用于避开 Vue 不能检测到属性被删除的限 制)

watch 和计算属性有什么区别?

参考回答:

通俗来讲,既能用 computed 实现又可以用 watch 监听来实现的功能,推荐用 computed, 重点在于 computed 的缓存功能

computed 计算属性是用来声明式的描述一个值依赖了其它的值,当所依赖的值或者变量 改变时, 计算属性也会跟着改变;

watch 监听的是已经在 data 中定义的变量,当该变量变化时,会触发 watch 中的方法。

Vue 双向绑定原理

参考回答:

Vue 数据双向绑定是通过数据劫持结合发布者-订阅者模式的方式来实现的 。利用了 Object.defineProperty() 这个方法重新定义了对象获取属性值(get)和设置属性值(set)。

v-model 是什么?有什么用呢?

参考回答:

一则语法糖,相当于 v-bind:value="xxx" 和 @input,意思是绑定了一个 value 属性的值, 子组件可对 value 属性监听, 通过$emit('input', xxx)的方式给父组件通讯 。 自己实现 v-model 方式的组件也是这样的思路。

axios 是什么? 怎样使用它? 怎么解决跨域的问题?

参考回答:

axios 的是一种异步请求,用法和 ajax 类似,安装 npm install axios --save 即可使用,请 求中包括 get,post,put, patch ,delete 等五种请求方式, 解决跨域可以在请求头中添加 Access-Control-Allow-Origin, 也可以在 index.js 文件中更改 proxyTable 配置等解决跨域 问题。

在 vue 项目中如何引入第三方库 (比如 jQuery) ?有哪些方法可以做到?

参考回答:

1 、绝对路径直接引入

在 index.html 中用 script 引入

<script src="./static/jquery-1.12.4.js"></script>           

然后在 webpack 中配置 external

externals: { 'jquery': 'jQuery' }           

在组件中使用时 import

import $ from 'jquery'           

2 、在 webpack 中配置 alias

resolve: { extensions: ['.js', '.vue', '.json'], alias: { '@': resolve('src'), 'jquery': resolve('static/jquery-1.12.4.js') } }           

然后在组件中 import

3 、在 webpack 中配置 plugins

plugins: [ new webpack.ProvidePlugin({ $: 'jquery' }) ]           

全局使用, 但在使用eslint 情况下会报错, 需要在使用了 $ 的代码前添加 /* eslint-disable*/ 来去掉 ESLint 的检查。

说说 Vue React angularjs jquery 的区别

参考回答:

JQuery 与另外几者最大的区别是, JQuery 是事件驱动, 其他两者是数据驱动。

JQuery 业务逻辑和 UI 更改该混在一起, UI 里面还参杂这交互逻辑, 让本来混乱的逻 辑更加混乱。

Angular, Vue 是双向绑定, 而 React 不是

其他还有设计理念上的区别等

Vue3.0 里为什么要用 Proxy API 替代 defineProperty API?

参考回答:

响应式优化。

a. defineProperty API 的局限性最大原因是它只能针对单例属性做监听。

Vue2.x 中的响应式实现正是基于 defineProperty 中的 descriptor,对 data 中的属性做了遍 历 + 递归, 为每个属性设置了 getter 、setter。

这也就是为什么 Vue 只能对 data 中预定义过的属性做出响应的原因, 在 Vue 中使用 下标的方式直接修改属性的值或者添加一个预先不存在的对象属性是无法做到setter 监 听的, 这是 defineProperty 的局限性。

b. ProxyAPI 的监听是针对一个对象的,那么对这个对象的所有操作会进入监听操作, 这 就完全可以代理所有属性, 将会带来很大的性能提升和更优的代码。

Proxy 可以理解成, 在目标对象之前架设一层“拦截”, 外界对该对象的访问, 都必须 先通过这层拦截, 因此提供了一种机制, 可以对外界的访问进行过滤和改写。

c. 响应式是惰性的

在 Vue.js 2.x 中,对于一个深层属性嵌套的对象,要劫持它内部深层次的变化,就需要 递归遍历这个对象, 执行 Object.defineProperty 把每一层对象数据都变成响应式的, 这 无疑会有很大的性能消耗。

在 Vue.js 3.0 中,使用 Proxy API 并不能监听到对象内部深层次的属性变化,因此它的 处理方式是在 getter 中去递归响应式,这样的好处是真正访问到的内部属性才会变成响 应式, 简单的可以说是按需实现响应式, 减少性能消耗。

基础用法:

前端工程师常见面试题(前端进阶)——Vue 框架

Vue3.0 编译做了哪些优化?

参考回答:

a. 生成 Block tree

Vue.js 2.x 的数据更新并触发重新渲染的粒度是组件级的,单个组件内部 需要遍历该组 件的整个 vnode 树。在 2.0 里,渲染效率的快慢与组件大小成正相关:组件越大,渲染 效率越慢 。并且, 对于一些静态节点, 又无数据更新, 这些遍历都是性能浪费。

Vue.js 3.0 做到了通过编译阶段对静态模板的分析, 编译生成了 Block tree 。 Block tree 是一个将模版基于动态节点指令切割的嵌套区块,每个 区块内部的节点结构是固定的, 每个区块只需要追踪自身包含的动态节点 。所以, 在 3.0 里, 渲染效率不再与模板大小 成正相关, 而是与模板中动态节点的数量成正相关。

b. slot 编译优化

Vue.js 2.x 中,如果有一个组件传入了slot,那么每次父组件更新的时候,会强制使子组 件 update, 造成性能的浪费。

Vue.js 3.0 优化了 slot 的生成, 使得非动态 slot 中属性的更新只会触发子组件的更新。

动态 slot 指的是在 slot 上面使用 v-if, v-for, 动态 slot 名字等会导致 slot 产生运行时动 态变化但是又无法被子组件 track 的操作。

c. diff 算法优化

Vue3.0 新特性 —— Composition API 与 React.js 中 Hooks 的异同点

参考回答:

a. React.js 中的 Hooks 基本使用

React Hooks 允许你 "勾入" 诸如组件状态和副作用处理等 React 功能中 。Hooks 只能 用在函数组件中,并允许我们在不需要创建类的情况下将状态、副作用处理和更多东西 带入组件中。

React 核心团队奉上的采纳策略是不反对类组件,所以你可以升级 React 版本、在新组 件中开始尝试 Hooks, 并保持既有组件不做任何更改。

案例:

前端工程师常见面试题(前端进阶)——Vue 框架

useState 和 useEffect 是 React Hooks 中的一些例子, 使得函数组件中也能增加状态和 运行副作用。

我们也可以自定义一个 Hooks, 它打开了代码复用性和扩展性的新大门。

b. Vue Composition API 基本使用

Vue Composition API 围绕一个新的组件选项 setup 而创建。setup() 为 Vue 组件提供了 状态 、计算值 、watcher 和生命周期钩子。

并没有让原来的 API ( Options-based API) 消失 。允许开发者 结合使用新旧两种 API (向下兼容) 。

前端工程师常见面试题(前端进阶)——Vue 框架

c. 原理

React hook 底层是基于链表实现,调用的条件是每次组件被 render 的时候都会顺序执行 所有的 hooks。

Vuehook 只会被注册调用一次, Vue 能避开这些麻烦的问题, 原因在于它对数据的响 应是基于 proxy 的,对数据直接代理观察 。 (这种场景下, 只要任何一个更改 data 的地 方, 相关的 function 或者 template 都会被重新计算, 因此避开了 React 可能遇到的性能 上的问题) 。

React 中, 数据更改的时候, 会导致重新 render, 重新 render 又会重新把 hooks 重新注 册一次, 所以 React 复杂程度会高一些。

Vue3.0 是如何变得更快的? (底层, 源码)

参考回答:

a. diff 方法优化

Vue2.x 中的虚拟 dom 是进行全量的对比。

Vue3.0 中新增了静态标记 ( PatchFlag) : 在与上次虚拟结点进行对比的时候, 值对比 带有 patch flag 的节点, 并且可以通过 flag 的信息得知当前节点要对比的具体内容化。

b. hoistStatic 静态提升

Vue2.x : 无论元素是否参与更新, 每次都会重新创建。

Vue3.0 : 对不参与更新的元素,只会被创建一次,之后会在每次渲染时候被不停的复用。

c. cacheHandlers 事件侦听器缓存

默认情况下 onClick 会被视为动态绑定, 所以每次都会去追踪它的变化但是因为是同一 个函数, 所以没有追踪变化, 直接缓存起来复用即可。

vue 要做权限管理该怎么做? 如果控制到按钮级别的权限怎么做?

参考回答:

按钮级别的权限:

vue 在 created 和 mounted 这两个生命周期中请求数据有什么区别呢?

参考回答:

看实际情况, 一般在 created (或 beforeRouter) 里面就可以, 如果涉及到需要页面加载 完成之后的话就用mounted。

在 created 的时候,视图中的 html 并没有渲染出来,所以此时如果直接去操作 html 的 dom 节点, 一定找不到相关的元素

而在mounted 中, 由于此时 html 已经渲染出来了, 所以可以直接操作 dom 节点, (此 时 document.getelementById 即可生效了) 。

说说你对 proxy 的理解

参考回答:

vue 的数据劫持有两个缺点:

1 、无法监听通过索引修改数组的值的变化

2 、无法监听 object 也就是对象的值的变化

所以vue2.x 中才会有$set 属性的存在

proxy 是 es6 中推出的新 api, 可以弥补以上两个缺点, 所以 vue3.x 版本用 proxy 替换 object.defineproperty。

继续阅读