1. 虚拟dom是什么?
// 本质是一个 js 对象 ==>下一步转化为 document.createElement() 执行
let obj = {
target:'ul', // 目标
attr: 'abc', // 属性
children: [{ // 子元素
target:'li',
attr: 'def',
}]
}
将 直接操作dom(影响浏览器性能)=>两份 js对象(虚拟dom)的比较(diff算法 即执行效率上的问题)局部更新
2. Vue data()为什么是一个函数?
闭包 =>特性?数据的私密性,延长变量生命周期
为了保持各个组件的数据隔离
3. Vue父子组件生命周期加载的时候执行顺序?
即 创建前后+挂载前后:
父beforeCreate
->父created
->父beforeMount
->子beforeCreate
->子created
->子beforeMount
->子mounted
->父mounted
4. Vue2 / 3中的响应式原理
4.1 vue2.x的响应式
-
官方描述:
- 当你把一个普通的 JavaScript 对家传入Vue 实例作为 data 选项,Vue 将遍历此对象所有的property,并使用 Object.defineProperty 把这些 property 全部转为 getter / setter。
-
实现原理:
-
对象类型:通过
Object.defineProperty()
对属性的读取、修改进行拦截(数据劫持)。 -
数组类型:通过重写更新数组的一系列方法来实现拦截。(对数组的变更方法进行了包裹)。
Object.defineProperty(data, 'count', { get () {}, set () {} })
-
-
存在问题:
- 新增属性、删除属性, 界面不会更新。
- 直接通过下标修改数组, 界面不会自动更新。
4.2 Vue3.x的响应式
- 实现原理:
-
通过
Proxy
(代理): 拦截对象中任意属性的变化, 包括:属性值的读写、属性的添加、属性的删除等。 -
通过
Reflect
(反射): 对源对象的属性进行操作。 -
new Proxy(data, { // 拦截读取属性值 get (target, prop) { return Reflect.get(target, prop) }, // 拦截设置属性值或添加新属性 set (target, prop, value) { return Reflect.set(target, prop, value) }, // 拦截删除属性 deleteProperty (target, prop) { return Reflect.deleteProperty(target, prop) } }) proxy.name = 'tom'
-
5. Vue 组件通讯的方式
props
和$emit
(父子组件)- 自定义事件(即中央事件总线
eventBus
)(上下级组件(跨多级)通讯) attrs
(收集除emit和props之外剩余参数和方法,用于兜底)$parent
(子向父组件通讯)$refs
(父向子组件通讯)provide / inject
(上下级组件(跨多级)通讯)vuex
(全局组件)
6. vuex 中 mutation / action 区别
mutation
:原子操作;必须同步代码;action
:可包含多个 mutation;可包含异步代码;
7. vue组件中data为什么是函数?
我们知道JS中实例对象是通过构造函数来创建的,每个构造函数可以new
出多个实例,每个实例都会继承原型上的属性和方法。那么在vue中,一个vue组件就是一个vue实例,当一个组件被复用多次就会创建多个实例。
- 如果data是对象,那么多次复用的组件在某一处改变了data数据,就会影响到其他处复用这个组件的地方,因为对象是引用数据类型,是对内存地址的引用,牵一发而动全身。
- 而如果data是一个函数的话,那么我们每次创建一个新的实例之后,就会调用这个新的data函数,返回一个新的对象,也就是给每一个data对象定义了一个新的内存地址,自己维护自己的数据。所以为了保证每个组件data的独立性,或者说是组件的可复用性,data就必须是一个函数。