一、compute计算属性的特点:
1、计算属性:解决模板中复杂的逻辑运算的问题;
2、计算属性只在内部逻辑依赖的数据发生变化的时候才会被再次调用;
3、计算属性缓存机制:当依赖发生改变时执行的方法,将结果挂载到实例上,以方法的名字为属性名,下次访问改属性时直接从实例上取值;
4、多次复用相同值的数据,计算属性只调用一次;
5、关注点在模板,处理模板中复杂夫人逻辑运算,将结果缓存起来给,模板使用。
二、实现compute的依赖收集:
1、把data返回的对象做响应式处理,遍历data每个属性通过Object.defineProperty给实例定义响应式属性;
2、收集compute对象中相关的依赖保存在computeData的对象中:
var computeData = {
[方法名]:{
value:方法执行的结果,
get:方法,
deep:[方法内部的依赖属性]
};
3、遍历computeData,通过Object.defineProperty给实例添加[方法名] 属性,之所以能够通过[方法名]直接访问到值,就是这个操作的原因。
4、当数据改变时,这个改变的属性的key给updata的方法,
5、updata方法通过key断computeData中有没有方法依赖到这个key,如果有就执行对于的get方法,将计算好的结果保存到实例[方法名] 属性中。
var App = {
data() {
return {
a: 1,
b: 2
}
},
compute: {
total() {
console.log('有依赖改变了...');
return this.a + this.b;
}
}
}
var myVue = (function() {
var computeData = {};
function Vue3(options) {
this._$data = options.data();
init(this, options.compute)
}
function init(vm, compute) {
reactiveData(vm)
reactiveCompute(vm, compute)
}
function reactiveData(vm) {
var _data = vm._$data;
for (let key in _data) {
(function(k) {
Reflect.defineProperty(vm, k, {
get() {
return vm._$data[k]
},
set(newValue) {
vm._$data[k] = newValue;
update(k)
}
})
}(key))
}
}
function reactiveCompute(vm, compute) {
_initcomputeData(vm, compute)
for (let key in computeData) {
(function(k) {
Reflect.defineProperty(vm, k, {
get() {
return computeData[k].value
},
set(newValue) {
computeData[k].value = newValue
}
})
}(key))
}
}
function _initcomputeData(vm, compute) {
for (let key in compute) {
var descriptor = Object.getOwnPropertyDescriptor(compute, key),
fn = descriptor.value.get ? descriptor.value.get : descriptor.value
computeData[key] = {}
computeData[key].value = fn.call(vm)
computeData[key].get = fn.bind(vm)
computeData[key].deep = _collectionDeep(fn)
}
}
function _collectionDeep(fn) {
var _collection = fn.toString().match(/this.(.+?)/g);
for (var i = 0; i < _collection.length; i++) {
_collection[i] = _collection[i].split('.')[1]
}
return _collection;
}
function update(key) {
var data=Object.values(computeData)
for (let item of data) {
if(item.deep.includes(key)){
item.value=item.get()
}
}
}
return Vue3;
}())
var vm = new myVue(App)
console.log(vm.total);
console.log(vm.total);
vm.a = 10 ;
console.log(vm.total);
console.log(vm.total);