Vue 面试知识点总结
栏目: JavaScript · 发布时间: 5年前
内容简介:本文内容来自网络,整理出来分享于大家~~参考至小册先来一张总体图,然后我们对每一部分详细分析。
本文内容来自网络,整理出来分享于大家~~
一、剖析 Vue.js 内部运行机制
参考至小册 剖析 Vue.js 内部运行机制
先来一张总体图,然后我们对每一部分详细分析。
1、初始化与挂载
new Vue
之后回调用一个 _init
方法去初始化,会初始化 data
、 props
、 methods
、 声明周期
、 watch
、 computed
、 事件
等。其中最重要的一点就是通过 Object.defineProperty
来设置 getter
和 setter
,从而实现数据的 【双向绑定响应式】 和 【依赖收集】 。
初始化完之后会调用一个 $mount
来实现挂载。如果是运行时编译,则不存在 render function
,存在 template
的情况需要重新编译。(我理解的意思:最开始我们需要去解析编译 template
中的内容,实现依赖收集和数据绑定,最后会生成一个 render function
.但是如果是运行时候比如响应数据的更改等,则不会在生成 render function
,而是通过 diff
算法直接操作虚拟 DOM
,实现正式结点的更新)。
2、响应式系统的实现原理
Vue是一款MVVM的框架,数据模型仅仅是普通的js对象,但是在操作这些对象的时候确可以及时的响应视图的变化。依赖的就是Vue的【响应式系统】。
面试题 —— 你了解Vue的MVVM吗?
MVVM包含三层:模型层Model,视图层View,控制层ViewModel.
联系:
- 视图层变化可以被viewModel监听到,从而更改Model中的数据。是通过 DOM事件监听 实现。
- Model层发生变化,可以被viewModel响应到view层,从而更新视图。是通过 数据绑定 。
总之:DOM事件监听和数据绑定是MVVM的关键。 DOM Listeners
监听页面所有View层DOM元素的变化,当发生变化, Model
层的数据随之变化; Data Bindings
监听 Model
层的数据,当数据发生变化, View
层的DOM元素随之变化。
(1)Object.defineProperty
首先我们来介绍一下 Object.defineProperty,Vue.js就是基于它实现「响应式系统」的。
Object.defineProperty(obj, prop, descriptor);
descriptor的一些属性,简单介绍几个属性:
- enumerable,属性是否可枚举,默认 false。
- configurable,属性是否可以被修改或者删除,默认 false。
- get,获取属性的方法。
- set,设置属性的方法。
- writable,当且仅当该属性的writable为true时,value才能被赋值运算符改变。默认为 false。
var o = {}; // 创建一个新对象 // 【1】在对象中添加一个属性与数据描述符的示例 Object.defineProperty(o, "a", { value : 37, writable : true, enumerable : true, configurable : true }); // 对象o拥有了属性a,值为37 // 【2】在对象中添加一个属性与存取描述符的示例 var bValue; Object.defineProperty(o, "b", { get : function(){ return bValue; }, set : function(newValue){ bValue = newValue; }, enumerable : true, configurable : true }); o.b = 38; // 对象o拥有了属性b,值为38 // o.b的值现在总是与bValue相同,除非重新定义o.b
(2)实现数据的观察(observer)
这是响应式系统最为重要的一步。利用的便是我们上面提到的 Object.defineProperty
。
实现一个简单的对数据的getter和setter监听:
// 遍历数据对象的每个属性,这里我们只做了一层,实际上会使用递归去处理深层次的数据 // 这里为了我们的方便理解,就假设是单层对象 function observer (value) { if (!value || (typeof value !== 'object')) { return; } Object.keys(value).forEach((key) => { defineReactive(value, key, value[key]); }); } // 函数模拟视图更新 function cb (val) { console.log("视图更新啦~", val); } // 数据对象成员的响应式监听 function defineReactive (obj, key, val) { Object.defineProperty(obj, key, { enumerable: true, // 可枚举 configurable: true, // 可配置 get: function reactiveGetter () { return val; // 当使用到我们的这个属性的时候会触发get方法,这里用来依赖收集,我们之后实现 }, set: function reactiveSetter (newVal) { // 监听数据的修改,模拟视图更新,其实这里的过程相当的复杂,diff是一个必经过程 if (newVal === val) return; val = newVal; cb(newVal); } }); } class Vue { constructor(options) { this._data = options.data; // 获取数据对象 observer(this._data); // 实现对数据中每个元素的观察,即为每个属性去设置get和set。 } } // 测试案例 let o = new Vue({ data: { test: "I am test." } }); o._data.test = "hello,test.";
上面我们实现的是一个简单的响应式原理案例,我们只是实现了对数据对象的观察。当我们的数据使用和被修改的时候会调用我们的自定义get和set方法。下面我们去了解一下,数据【依赖收集】。
(3)依赖收集
为什么要进行依赖收集呢?
new Vue({ template: `<div> <span>{{text1}}</span> <span>{{text2}}</span> <div>`, data: { text1: 'text1', text2: 'text2', text3: 'text3' } });
上面例子中,text1,text2使用了一次,text3未使用。
如果我们对某一个数据进行了修改,那么我们应该知道的哪些地方使用了该数据,为了我们视图的更新做好准备。
「依赖收集」会让 text1
这个数据知道“哦~有两个地方依赖我的数据,我变化的时候需要通知它们~”。
订阅者Dep
class Dep { constructor () { /* 用来存放Watcher对象的数组 */ this.subs = []; } /* 在subs中添加一个Watcher对象 */ addSub (sub) { this.subs.push(sub); } /* 通知所有Watcher对象更新视图 */ notify () { this.subs.forEach((sub) => { sub.update(); }) } }
订阅者对象含有两个方法,addSub用来收集watcher对象,notify用来通知watcher对象去更新视图。
观察者Watcher
class Watcher { constructor () { /* 在new一个Watcher对象时将该对象赋值给Dep.target,在get中会用到 */ Dep.target = this; } /* 更新视图的方法 */ update () { console.log("视图更新啦~"); } } Dep.target = null;
观察者对象在实例化的时候就需要绑定它所属的Dep。同时还有一个update方法去更新视图。
依赖收集原理
function defineReactive (obj, key, val) { /* 一个Dep类对象 */ const dep = new Dep(); Object.defineProperty(obj, key, { enumerable: true, configurable: true, get: function reactiveGetter () { /* 将Dep.target(即当前的Watcher对象存入dep的subs中) */ dep.addSub(Dep.target); return val; }, set: function reactiveSetter (newVal) { if (newVal === val) return; /* 在set的时候触发dep的notify来通知所有的Watcher对象更新视图 */ dep.notify(); } }); } class Vue { constructor(options) { this._data = options.data; observer(this._data); /* 新建一个Watcher观察者对象,这时候Dep.target会指向这个Watcher对象*/ // 实例化一个观察者 new Watcher(); /* 在这里模拟render的过程,为了触发test属性的get函数 */ console.log('render~', this._data.test); // 触发get之后,会将上面刚实例化的watcher对象,添加到Dep对象中。 // 注:这里只实例化了一个watcher,其实watcher对象没有我们上诉的那么简单,它记录的是当前引用的相关信息。为方便下次数据的更新时候,去更新视图 } }
当触发一个属性的get方法后,会执行我们的依赖收集。首先实例化一个watcher对象,这个watcher对象有这个属性的更新视图的方法。然后通过Dep的addSub方法将该watcher对象添加到Dep订阅者中。
【依赖收集】的关键条件:(1)触发get方法 (2)新建一个watcher对象
总结: 到了这里我们已经吧响应式系统学了,主要是get进行依赖收集,set中用过watcher观察者去更新视图。
以上所述就是小编给大家介绍的《Vue 面试知识点总结》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。