vue面试题(一)正在重新整理

1.输入一个 URL到浏览器整个过程发生了什么?ok

1.浏览器查找当前 URL是否存有缓存,并检查这个缓存是否过期
2.DNS 解析 URL 对应的 IP
3.根据 IP 建立 TCP 连接(三次握手)
4.发送 http 请求
5.服务器处理请求,返回内容,浏览器接受 HTTP 响应
6.浏览器解析并渲染页面
7.关闭 TCP 连接(四次握手)
[https://juejin.cn/post/6844903832435032072]

2 什么是事件代理(事件委托)? ok

事件委托的原理:不给每个子节点单独设置事件监听器,
而是设置在其父节点上,然后利用冒泡原理设置每个子节点

3 事件委托的优点有哪些 ?

1. 减少内存消耗和 dom 操作
2. 动态绑定事件。因为事件绑定在父级元素 所以新增的元素也能触发同样的事件

4 addEventListener 默认是捕获还是冒泡

默认是冒泡
addEventListener第三个参数默认为 false 代表执行事件冒泡行为。
当为 true 时执行事件捕获行为。

5. css的渲染层合成是什么?

在 DOM 树中每个节点都会对应一个渲染对象(RenderObject),
当它们的渲染对象处于相同的坐标空间(z 轴空间)时,
就会形成一个 RenderLayers也就是渲染层。
渲染层将保证页面元素以正确的顺序堆叠,这时候就会出现层合成(composite)。

6.层合成的作用

层合成的作用:从而正确处理透明【元素和重叠】元素的显示。
因为一旦图层的合并顺序出错,将会导致页面显示异常。

7 webpack Plugin 和 Loader 的区别

从运行时机的角度区分
1. loader运行在打包文件之前
2. plugin在整个编译周期都起作用
https://juejin.cn/post/6844904150988226574
https://www.cnblogs.com/yuantai/p/14082487.html

7.1 webpack的缺点

由于webpack本身只能打包commonjs规范的js文件,
所以针对css,图片等文件没法打包,
就需要引入第三方的模块进行打包。
如css-loader 和 style-loader 模块 处理css的

7.2 babel-loader 和 babel-core 模块是用来干嘛的?

是为了把es6的代码转成 es5

8. css 优先级是怎么计算的

第一优先级:!important 会覆盖页面内任何位置的元素样式
1.内联样式,如 style="color: green",权值为 1000
2.ID 选择器,如#app,权值为 0100
3.类、伪类、属性选择器,如.foo, :first-child, div[class="foo"],权值为 0010
4.标签、伪元素选择器,如 div::first-line,权值为 0001

5.通配符、子类选择器、兄弟选择器,如*, >, +,权值为 0000
6.继承的样式没有权值

9. http 状态码 含义

http 状态码 204 (无内容) 服务器成功处理了请求,但没有返回任何内容

http 状态码 301 (永久移动) 请求的网页已永久移动到新位置。 
http 状态码 302 (临时移动) 但请求者继续使用原有位置来进行以后的请求。

http 状态码 400 (错误请求) 服务器不理解请求的语法(一般为参数错误)。
http 状态码 401 (未授权) 要求身份验证,或者身份过期。
http 状态码 403  服务器已经理解请求,但是拒绝执行它。(一般为客户端的用户权限不够)
http 状态码 404 (未找到) 服务器找不到请求的网页。

500 服务器遇到了一个未曾预料的状况,无法完成对请求的处理,会在程序码出错时出现。
501 服务器不支持当前请求所需要的某个功能。
502 作为网关或者代理工作的服务器尝试执行请求时,从上游服务器接收到无效的响应。
503 由于临时的服务器维护或者过载,服务器当前无法处理请求。

上面这个阶段已经完成了 开始新的阶段===========================================================================

1=>为什么data是一个函数

每复用一次组件,就会返回一分新的data。
也就说:【每个组件实例创建】一个【私有】的数据空间。各个组件维护各自的数据。
如果单纯的写成对象形式,那么所有组件实例共用了一份data.
就会造成一个发生改变,全部都会发生改变。  
data(){  return{ }  }

2=> vue的生命周期 8+2 ok

我们都知道vue常用的8个生命周期,但是这几个生命周期你熟悉吗?
activated keep-alive 专属,组件被激活时调用 [ai k t v ti de], 第一次进入也会触发activated  
deactivated keep-alive 专属,组件离开时调用 【di ai k t v ti de】
errorCaptured是vue2.5.0版本新增的一个钩子函数, [error cai p true d]
它主要用来捕获一个来自子孙组件的错误]可以应用在前端监控中。

4=> 怎样理解 Vue 的单项数据流 ok

数据总是从父组件传到子组件,
子组件没有权利修改父组件传过来的数据,[如果你强行更改,控制台会报警,告诉你这个是单向的]
只能请求父组件对原始数据进行修改。
这样会防止从子组件意外改变父组件的状态,
从而导致你的应用的数据流向难以理解。

5=> v-if 和 v-for 为什么不建议一起使用 ok

vue2中先解析v-for然后在解析v-if,[会造成消耗性能]
如果遇到需要同时使用时可以嵌套一层元素  
<template></template>

6 template 的作用

template的作用是模板占位符,可帮助我们包裹元素.
但在循环过程当中,template不会被渲染到页面上。
template标签不支持v-show指令,即v-show="false"对template标签来说不起作用。
template标签支持v-if、v-else-if、v-else、v-for这些指令。

6.1=> vue3 v-for和v-if做了更改

很幸运 vue 3.x 中, v-if 总是优先于 v-for。

07==> Vue的父子组件生命周期钩子函数执行顺序 ok

加载渲染过程
父beforeCreate -> 父created -> 父beforeMount ->
->子beforeCreate -> 子created -> 子beforeMount -> 子mounted -> 父mounted
【你可以理解页面渲染,这样就好理解了】

子组件更新过程
父beforeUpdate -> 子beforeUpdate -> 子updated -> 父updated

父组件更新过程
父beforeUpdate -> 父updated

销毁过程
父beforeDestroy -> 子beforeDestroy -> 子destroyed -> 父destroyed

8. 虚拟DOM是什么?有什么优缺点?

虚拟Dom的产生原因:由于在浏览器中频繁操作DOM代价是很昂贵的。会产生一定性能问题。

Vue2的Virtual DOM 借鉴了开源库 snabbdom 的实现。
Virtual DOM本质就是用一个[原生的JS对象]去[描述]一个[DOM节点],是对真实DOM的一层抽象。
上面这一句话就翻译为代码 就是
<div>
  <p>123</p>
</div>
对应的virtual DOM(伪代码):
var Vnode = {
 tag: 'div',
 children: [
  { tag: 'p', text: '123' }
 ]
};

9 虚拟DOM优点:

1、保证性能下限:虽然它的性能并不是最优的;
但是比起粗暴的DOM操作,还有不错的性能,

2、无需手动操作DOM,只需要写好代码逻辑,
框架会【根据虚拟DOM】和【数据双向绑定】,
帮我们自动更新视图,提高我们的开发效率。

3、跨平台:虚拟DOM可以进行更方便地跨平台操作,

10. 虚拟DOM缺点:

1、无法进行极致优化:虽然虚拟DOM + 合理的优化,足以应对大部分应用的性能需要,
但在一些【性能要求极高】的应用中虚拟DOM无法没满足。
2、首次渲染大量DOM时,由于多了一层DOM计算,会比innerHTML插入慢。

上面这个阶段已经完成了 开始新的阶段====================================================

1=> Vue3.0 和 2.0 的【响应式原理】区别

1.Vue3.x 改用 Proxy[pu luo k she] 替代 Object.defineProperty[di fai n prɒ pə ti]。
2.Object.defineProperty无法直接监听对象新增或者删除的属性。Proxy可以.
3.Object.defineProperty无法一次性监听所有属性,需要通过Object.keys进行遍历。而Proxy不需要,可以直接监听所有属性。
4.Object.defineProperty我们无法让Map、Set这类数据类型转变为响应式,Proxy可以。

Object.defineProperty 
1. Object.defineProperty对【对象新增或者删除】的属性无法监听到
2. vue2 中修改数组的索引和长度无法被监控到。

2=> Vuex 页面刷新数据丢失怎么解决?

在刷新页面的时候,将vuex中的只存在本地
也可以使用第三方插件。  vuex-persist (pəˈsɪ s t])插件,
它是为 Vuex 持久化储存而生的一个插件。

3 你都做过哪些 Vue 的性能优化?

语法方面:
v-if 和 v-show 区分使用场景
computed 和 watch 区分场景使用
v-for 遍历必须加 key,key最好是id值,且避免同时使用 v-if

//数据方面
对象层级不要过深,否则性能就会差。
不需要响应式的数据不要放在 data 中(可以使用 Object.freeze() 冻结数据)

// 加载-缓存
路由懒加载
第三方插件的按需加载
适当采用 keep-alive 缓存组件
防抖、节流的运用

4 Vue.mixin 的使用场景和原理

在开发的过程中我们会遇见相同或者相似的逻辑代码。
可以通过vue的 mixin 功能抽离公共的业务逻辑,
然后通过impor再组件中引入。通过mixins注册进来。
这样我们就可以使用mixin中共同的业务逻辑

<script>
import { mixinmethods} from "../mixin.js"
    export default {
        // mixins是固定的,里面传入一个数组
        mixins:[mixinmethods]
    }
</script>

如果组件中data数据与混合中的数据重复,会进行合并。使用data中的数据。
【组件中是可以直接使用混合中的数据的,自己理解】
需要注意的是:声明周期不会进行合并
如果你在混合中使用了生命周期,组件中也是用生命周期。
组件和混合中的生命周期都会被执行。正常情况下,先执行组件中的生命周期。

5. nextTick 使用场景和原理

场景:当组件使用v-if进行切换时,值为true的时候。
立刻获取组件的实例,就会出现undefiend
为什么会出现undefined?
Vue 实现响应式并不是数据发生变化之后 DOM 立即变化,而是按一定的策略进行 DOM 的更新。

原理:
nextTick 将回调延迟到下次 DOM 更新循环之后执行

6、 keep-alive 使用场景和原理

keep-alive 是 Vue 内置的一个组件,可以实现组件缓存,当组件切换时不会对当前组件进行卸载。
常用的两个属性 include/exclude,符合条件的组件或者页面进行缓存。 [include 是页面中的name ]
include的类型可以是字符串,数组,正则。 其中 exclude的优先级高于include

两个生命周期 activated/deactivated,用来得知当前组件是否处理活跃状态。
keep-alive 运用了 LRU 算法,选择最近【久未使用的组件】予以淘汰。
keep-alive其实还有一个属性max, 最大允许缓存多少个,如果超出最大个数。
会将已缓存组件中最久没有被访问的实例会被销毁掉。
[exs k lu d] exclude 排除

7、Vue.set 方法原理

在两种情况下修改 Vue 是不会触发视图更新的。 
1、给响应式对象新增属性,这个时候是不会跟新视图的
2、直接更改【数组下标】来修改数组的值。

我们可以通过 Vue.set(this.userInfo, 'sex' ,'男') 
或者 this.$forceUpdate() 来解决这个问题

set 原理如下
因为是响应式数据,
我们给对象和数组本身新增了__ob__属性,代表的是 Observer【饿 b zɜ və(r)】 实例。
如对象新增不存在的属性,首先会把新的属性进行响应式跟踪。
当数据发生变化后,watcher【ˈwɑːtʃər]】 去更新视图.
【使用splice方法向数组内添加元素时】该元素会自动被变成响应式的
源码:https://blog.csdn.net/leelxp/article/details/107212555

8 assets 和static【不会打包】的区别

答:相同点:assets【a sai s 】和static两个都是存放静态资源文件,
图片,字体图标,都可以放在这两个文件下。

不相同点:
build的时候会将assets中放置的静态资源文件【会进行】打包压缩上传.
static中放置的静态资源文件就【不会】打包压缩
巧计:听读音, assets 有压缩。

9.vue的两个核心点

答:数据驱动、组件系统
数据驱动:保证数据和视图的一致性。
组件系统:页面中的所有模块可以看作全部是由[组件树]构成的。

10 vue-router 有哪几种导航钩子?

答:三种,
第一种:是全局导航钩子:
router.beforeEach(to,from,next){}
router.afterEach(to,from,next){} 
作用:跳转前进行判断拦截。 2个

第二种:组件内的钩子   
beforeRouteEnter (to, from, next) { }
beforeRouteLeave(to, from, next){ }

第三种:单独路由独享钩子
beforEnter:(to, form,next) => { 
	
}

上面这个阶段已经完成了 开始新的阶段====================================================

3. $route 和 $router 的区别

答:$router是VueRouter的实例,{可以导航到不同的URL,使用$router.push方法。}
返回上一个历史用$router.go(-1) 或者 $router.back()

$route为当前router跳转对象。里面可以获取当前路由的name,path,parmas等。

4.vue初始化页面闪动问题

有些时候看到类似于{{message}}的字样,
虽然一般情况下这个时间很短暂,但是我们还是有必要让解决这个问题的。
首先在css里加上
[v-cloak] { [k ləʊ k][掩盖]
	display: none; 
}
如果没有彻底解决问题,则在根元素加上:style="{display: 'block'}"

还有一种方法:使用v-text来解决

5. Vue2中注册在router-link上事件click无效解决方法

使用@click.native。原因:router-link会阻止click事件,.native指直接监听一个原生事件。
在vue3中native被移除了

6. Vue里面router-link在电脑上有用,在安卓上没反应怎么解决?

答:Vue路由在Android机上有问题。
【通过工具查看一下该标签是否被正确解析了,如果没有使用使用一些插件来进行解决】babel问题,

7. vue-loader是什么?使用它的用途有哪些?

答:vue文件的一个加载器,将template/js/style转换成js模块

8. 说说你对 SPA 单页面的理解,它的优缺点分别是什么?

1.用户体验好、快,内容的改变不需要重新加载整个页面。
2.SPA 相对对服务器压力小;

缺点:
初次加载耗时多:因为要在加载页面的时候将 JavaScript、CSS 统一加载,
SEO 难度较大:由于所有的内容都在一个页面中动态替换显示,所以在 SEO 上其有着天然的弱势。

9 vue常用的修饰符

表单修饰符: 
lazy(当光标离开标签时,会将值赋值给value)
trim(去掉两边的空格)
number(将用户输入的值转为数字类型,但如果这个值无法被parseFloat解析,则返回原来的值)

事件修饰符:
stop 阻止事件的冒泡。相当于event.stopPropagation()方法
capture 事件捕获。从顶层往下触发。
prevent 阻止了事件的默认行为。相当event.preventDefault()方法
self只触发自己范围内的事件。不包含子元素
once绑定的事件只能触发一次
native在自定义组件标签上绑定原生事件

10. Proxy 与 Object.defineProperty 优劣对比

1.Object.defineProperty无法直接监听对象新增或者删除的属性。Proxy可以
2.Object.defineProperty无法一次性监听所有属性,需要通过Object.keys进行遍历。而Proxy不需要,可以直接监听所有属性。
3.Proxy代理整个对象。Object.defineProperty只能够处理对象上的某个属性,多个属性需要遍历;
4.Object.defineProperty我们无法让Map、Set这类数据类型转变为响应式,Proxy可以。
5.Proxy 作为新标准将受到浏览器厂商重点持续的性能优化,也就是传说中的新标准的性能红利。

Object.defineProperty 的优势如下:
兼容性好,支持 IE9。
而 Proxy 的存在浏览器兼容性问题,而且无法用 polyfill 磨平,
因此 Vue 的作者才声明需要等到下个大版本( 3.0 )才能用 Proxy 重写。

上面这个阶段已经完成了 开始新的阶段====================================================

1.v-show 与 v-if 有什么区别?ok+

v-if 是真正的条件渲染,也是惰性的;
如果在初始渲染时条件为假,则什么也不做——
直到[条件第一次变为真]时,才会开始渲染

v-show 不管初始条件是什么,元素总是会被渲染.
并且只是简单地基于 CSS 的 “display” 属性进行切换。

频繁切换使用v-show, 切换较少使用v-if

2.computed 和 watch 的区别和运用的场景?ok

computed: 是计算属性,computed 的值有缓存。
只有它[依赖的属性值]发生改变,computed 的值时才会重新计算。
他必须有返回值

watch: 更多的是「观察」的作用,类似于某些[数据的监听回调]。
每当监听的数据变化时,都会执行回调,进行后续操作。

场景:
form表单中的input都必须有有值, 按钮才能够进行点击 我们就可以使用computed.
computed 一般是多个值影响一个值。

当我们需要在数据变化时【执行异步】或【开销较大】的操作时,应该使用 watch
watch 一般是是一个值影响多个值

ps:computed依赖的属性只有是响应式属性发生变化才会重新计算,若不是响应式数据则不会跟新。

3. v-model 的原理?ok

v-model 在内部为不同的输入元素[使用不同的属性]并[抛出不同]的事件:
text 和 textarea 元素使用 value 属性和 input 事件;
checkbox 和 radio 使用 checked 属性和 change 事件;
select 字段将 value 作为 prop 并将 change 作为事件。

4. vue-router 路由模式有几种? ok

vue-router 有 3 种路由模式:hash、history、abstract
hash: 使用 hash 值来作路由。支持所有浏览器。
history : 有些浏览器不支持
abstract : [ æ bˈstræ k t] 支持所有 JavaScript 运行环境,如 Node.js 服务器端。
如果发现没有浏览器的 API,路由【会自动强制进入】这个模式.

6. 虚拟 DOM 实现原理?

虚拟 DOM 的实现原理主要包括以下 3 部分:
1.用一个[原生的JS对象]去[描述]一个[DOM节点],是对真实DOM的一层抽象。
2.diff 算法 — 比较两棵虚拟 DOM 树的差异;【dif算法比较两颗树直接的差异】
3.pach 【帕其】算法 — 将两【个虚拟DOM对象的差异】应用到【真正的 DOM 树】。

7. Vue 中的 key 有什么作用? ok

key 是 Vue中vnode的唯一标记,通过这个key,我们的diff操作可以更准确、更快速。
1:通过 sameNode函数对比key值(a.key === b.key ),避免了就地复用的情况,所以会更加的准确 
2.更快速:利用key的唯一性生成map对象,来获取对应节点,比遍历方式更快。

8. key的实际运用场景

1.处理勾选时候的bug。 比如列表中有 【A,B,C】
我们勾选B,向列表的最前面中添加A1,列表是[A1,A,B,C]此时却勾选了A

2.key值应该是唯一的。最好使用id值。
为什么使用id值,而不是index

上面这个阶段已经完成了 开始新的阶段====================================================

1.Vue是什么?(了解就可以)

1.是一套用于构建用户界面的渐进式框架,自底向上逐层应用。
2.vue核心只关注视图层,容易上手,而且方便与第三方库整合。
3.完全能够为复杂的单页应用提供驱动。

2.Vue的优点 (了解)

1.开发者:只关注视图,简单易学,
2.双向数据绑定,操作数据简单
3.组件化,构建单页面有优势
4.视图数据分离,使用数据更方便
5.虚拟DOM+diff算法,提高页面的渲染速度

3.watch的使用

watch: {
    firstName(newName, oldName) {
      // newName 是新值,oldName旧值
    },
    immediate: true,
} 
immediate: 立即监视, deep : 深度监视 

4.你对slot的理解

slot是 vue 内容分发机制,插槽是(子组件的)一个模板标签。
这个标签由父组件决定,有默认插槽,具名插槽,作用域插槽。

默认:匿名插槽,直接在组件送写slot。一个组件只能有一个匿名
具名:带有名字的插槽,slot name='xxx'可以有多个。
作用域: 可以将子组件内部的数据传递给父组件,父组件根据子组件的数据决定如何渲染

5.Vue模版编译原理

解析阶段:对 template 字符串解析,将标签,指令,属性转为抽象【语法树 AST】
优化阶段:遍历 AST 找出其中的静态节点进行标记,方便在重新渲染的时候进行 diff 比较时 ,跳过一些静态节点
生成阶段:将 AST 转为 render函数字符串

6 Vue 响应式原理

整体思路是数据劫持+观察者模式
数据劫持核心是 defineReactive 函数,
主要使用 Object.defineProperty 将属性进行劫持(只会劫持已经存在的属性),
数组则是通过重写数组的原型方法,对数组的7种方法进行拦截。
当页面使用对应属性时,每个属性都拥有自己的 dep 属性,
它[dep]存放所依赖的 watcher(依赖收集),
当属性变化后会通知自己对应的 watcher 去更新(派发更新)

监听的大致过程是:observe 函数会判断传递过来的值是对象还是数组。
{你看的:分别通过  Object.prototype.toString.call(value) === "[object Object]"  ||  Array.isArray(value)}
如果是对象,调用 Observer类,在 constructor 中调用 walk 函数。
walk函数做了:对象上的所有属性依次进行观测,并调用defineReactive函数,defineReactive(data, key, value);
如果value还是一个对象会继续走一遍,层层遍历一直到value不是对象才停止

Object.defineProperty 中get做依赖收集的过程。set是 设置新值,做派发更新过程 
这样就可以做到据变动了会自动更新视图


题外话 1==>如果监听的是对象,对象上的所有属性依次进行观测。
使用了 let keys = Object.keys(data);返回了所有对象的key值。

题外话 2==>  如果value还是一个对象会继续走一遍 odefineReactive,
层层遍历一直到value不是对象才停止

题外话 3 ==> Object.defineProperty中中get做依赖收集的过程。
set是 设置新值,做派发更新过程 

这样的劫持方式对数组有什么影响

这样递归的方式其实无论是对象还是数组都进行了观测,
但是我们想一下此时如果 data 包含数组比如 a:[1,2,3,4,5] 
那么我们根据下标可以直接修改数据也能触发 set 
但是如果一个数组里面有上千上万个元素
每一个元素下标都添加 get 和 set 方法 
这样对于性能来说是承担不起的,所以此方法只用来劫持对象
则是对数组的方法进行了重写

8 vue对数组观察的过程

Observer 类中判断是否是数组。通过 Array.isArray(value)
重写数组原型方法来,对数组的七种方法进行拦截。
如果数组里面还包含数组需要递归判断。递归则是通过了observeArray来处理

每个响应式数据增加了一个不可枚举的__ob__属性,
并且指向了 Observer 实例,
那么我们首先可以根据这个属性来防止已经被响应式观察的数据反复被观测,
其次,响应式数据可以使用__ob__来获取 Observer 实例的相关方法 这对数组很关键

题外话1:
因为对数组下标的拦截太浪费性能 ,对Observer构造函数传入的数据参数增加了数组的判断

9. Object.defineProperty 缺点?

对象新增或者删除的属性无法被 set 监听到 
只有对象[本身存在]的属性修改才会被劫持

10. Vue nextTick 原理

Vue 在更新 DOM 是异步的,当监听数据变化后,vue会开启一个队列。
并缓冲同一个事件在循环中发生【当所有数据变化后】,
如果同一个 watcher 被多次触发,只会被推入到队列中一次。
这种缓冲的意义在于,去除重复的数据,可以避免不必要计算和DOM操作。
Vue内部对异步队列尝试使用 Promise.then、
然后时是 MutationObserver 和 setImmediate 
如果前两者都不支持使用  setTimeout(fn, 0) 代替。
对当前环境进行不断的降级处理,它之所以这样做,是为了提升性能。
【mjuːˈteɪ ʃn]】 Mutation   突变;变异;基因突变
【ɪn mi di ət 】   
也就是说我们在设置数据的时候,( this.msg = 'some thing' )
Vue并没有马上去更新DOM,而是将这个操作放进一个队列中
如果我们重复执行的话,队列还会进行去重操作。
等待同一事件【循环】所有数据变化完成之后。
会将事件从队列拿出来。

这样做主要是为了提升性能,
如果循环100次就要更新100次DOM,是非常消耗性能的。
但是如果等【事件循环完成】之后更新DOM,只需要更新1次。

题外话1:如果多次调用nextTick,只会执行一次异步 ,
等异步队列清空之后再把标志变为false

11.npm与yarn的区别

1.npm是按照队列执行每个package,也就是说必须要等到当前 package 安装完成之后,才能继续后面的安装。
而 Yarn 是同步执行所有任务,提高了性能。 
2.如果之前已经安装过一个软件包,用Yarn再次安装时之间从缓存中获取,就不用像npm那样再从网络下载了。

上面这个阶段已经完成了 开始新的阶段====================================================

posted @ 2021-12-07 22:07  南风晚来晚相识  阅读(248)  评论(0编辑  收藏  举报