大家想看源码的,有大佬已经在GitHub上写了MVVM,大家有兴趣可以去GitHub搜索MVVM第一个就是,里面是中文。
具体分析一下如何实现:数据代理。(这些也是前端面试中Vue必问的知识点)
分析之前大家需要了解一下JavaScript有关对象的方法和属性:
Object.keys(),给此方法传入一个对象,它会返回一个数组,这个数组中的值是由传入的对象中的K值所组成(K值,KV键值对中的K,K是属性,V是值)。
在MVVM中,在实例化对象中传入配置对象,要将配置对象中的data中的属性拿出来,然后进行遍历
Object.keys(data).forEach(function(key) {
// 调用实例原型上的方法,将遍历的属性值添加到当前实例上
me._proxyData(key);
});
Object.defineProperty(),方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。此方法接受三个参数,第一个是目标对象;第二个参数是向目标属性中添加或修改的属性;第三个参数传入一个配置对象,此配置对象中包括:configurable为true,添加或修改的属性值可以被修改或删除,默认值为false,不能修改或删除;enumerable是否能被枚举,设置为true时可以被枚举,设置为false时不能被枚举
//me是指实例化的那个对象,key中保存的是data中遍历拿到的每一个属性
Object.defineProperty(me, key, {
//此属性不能被修改
configurable: false,
//此属性可以被枚举
enumerable: true,
//将set好的值写入到属性中
get: function proxyGetter() {
return me._data[key];
},
//设置该属性的值为newVal
set: function proxySetter(newVal) {
me._data[key] = newVal;
}
});
数据代理:
需求:
1、为何要产生数据代理?2、何为数据代理?
解决:
1、数据代理方便程序员直接使用data中的属性。
2、在Vue语法中,不用vm.data.属性去获取值,而是直接使用{{属性}}向标签中添加文本即可。
具体实现的步骤:
1、将配置参数对象传入MVVM构造函数中(在Vue中是Vue构造函数,在此篇文章中都使用MVVM构造函数来说明,Vue源码中的实现和MVVM中的类似)。
2、将传入参数指针修改为this.$options,给配置对象设定新的指向,指向其堆内存中。
3、给访问data中的属性设置新的指向,分别为_data和data。
4、将this保存在变量me中。
5、使用对象中的key方法和数组的forEach方法将对象中每一个属性遍历出来
function MVVM(options) {
// 接受实例的配置参数,配置参数为对象,将对象存在$options方法中
this.$options = options || {};
// 将配置对象中的data的动态属性值拿出来赋值给实例_data属性上
var data = this._data = this.$options.data;
// 将指向实例this存在me中
var me = this;
// 数据代理
// 实现 vm.xxx -> vm._data.xxx
Object.keys(data).forEach(function(key) {
// 调用实例原型上的方法,将遍历的属性值添加到当前实例上
me._proxyData(key);
});
this._initComputed();
observe(data, this);
this.$compile = new Compile(options.el || document.body, this)
}
6、给构造函数MVVM原型设置方法_proxyData,每个遍历的属性都调用此方法,向me实例中添加属性,并将值赋值给新添加的属性。
MVVM.prototype = {
constructor: MVVM,
$watch: function(key, cb, options) {
new Watcher(this, key, cb);
},
// 实例原型上的方法接受三个参数,第一个参数为遍历拿到的属性值,第二个参数为属性的v,
_proxyData: function(key, setter, getter) {
var me = this;
setter = setter ||
Object.defineProperty(me, key, {
configurable: false,
enumerable: true,
get: function proxyGetter() {
return me._data[key];
},
set: function proxySetter(newVal) {
me._data[key] = newVal;
}
});
},
总结:
以上步骤就实现了数据代理,主要使用到了Object对象中的keys方法和defineProperty方法,通过keys方法将data中的每一个属性拿到,在通过defineProperty向new MVVM实例中添加data的属性,此时vm实例就可以直接访问到data中的属性
console.dir(vm._data.msg)
// 数据代理----Vue中有数据代理
console.log(vm.msg)
// 数据代理:data对象中的数据需要通过vm去访问
// vm是代理者,data是被代理者
// 面试题: 说说你对Vue的理解
以后还会分析Vue中的模板解析、数据劫持。