Vue.js中的computed工作原理
JS属性:
JavaScript有一个特性是Object.defineProperty,它能做很多事,但我在这篇文章只专注于这个方法中的一个:
varperson={};
Object.defineProperty(person,'age',{
get:function(){
console.log("Gettingtheage");
return25;
}
});
console.log("Theageis",person.age);
//Prints:
//
//Gettingtheage
//Theageis25
(Obeject.defineProperty是Object的一个方法,第一个参数是对象名称,第二个参数是要设置的属性名,第三个参数是一个对象,它可以设置这个属性是否可修改、可写等,而这篇文章主要使用的是Obeject.defineProperty的访问器属性,感兴趣的朋友可以自行google或者查看Js高及程序设计)
尽管person.age看起来像是访问了对象的一个属性,但其实在内部我们是运行了一个函数。
一个基本可响应的Vue.js
Vue.js内部构建了一个可以将普通的对象转化为可以被观察的值(响应属性),下面为大家展示一个简化版的如何添加响应属性的案例:
functiondefineReactive(obj,key,val){
Object.defineProperty(obj,key,{
get:function(){
returnval;
},
set:function(newValue){
val=newValue;
}
})
};
//创建一个对象
varperson={};
//添加可响应的属性"age"和"country"
defineReactive(person,'age',25);
defineReactive(person,'country','Brazil');
//现在你可以随意使用person.age了
if(person.age<18){
return'minor';
}
else{
return'adult';
}
//设置person.country的值
person.country='Russia';
有趣的是,25和‘Brazil'还是一个闭包内部的变量,只有当赋给它们新值的时候val才会改变。person.country并不拥有'Brazil'这个值,而是getter这个函数拥有'Brazil'这个值。
声明一个计算属性
让我们创建一个定义计算属性的函数defineComputed。这个函数就跟大家平时使用computed时的一样。
defineComputed(
person,//计算属性就声明在这个对象上
'status',//计算属性的名称
function(){//实际返回计算属性值的函数
console.log("statusgettercalled")
if(person.age<18){
return'minor';
}
else{
return'adult';
}
},
function(newValue){
//当计算属性值更新时调用的函数
console.log("statushaschangedto",newValue)
}
});
//我们可以像使用一般的属性一样使用计算属性
console.log("Theperson'sstatusis:",person.status);
让我们写一个简单的defineComputed函数,它支持调用计算方法,但目前不需要它支持updateCallback。
functiondefineComputed(obj,key,computeFunc,updateCallback){
Object.defineProperty(obj,key,{
get:function(){
//执行计算函数并且返回值
returncomputeFunc();
},
set:function(){
//什么也不做,不需要设定计算属性的值
}
})
}
这个函数有两个问题:
每次访问计算属性时都会执行一次计算函数computeFunc()
它不知道什么时候更新(即当我们更新某个data中的属性,计算属性中也会更新这个data属性)
//我希望最终函数执行后是这个效果:每当person.age更新值的时候,person.status也同步更新 person.age=17; //console:status的值为minor person.age=22; //console:status的值为adult
增加一个依赖项
让我们增加一个全局变量Dep:
varDep={
target:null
};
这是一个依赖项,接着我们用一个骚操作来更新defineComputed函数:
functiondefineComputed(obj,key,computeFunc,updateCallback){
varonDependencyUpdated=function(){
//TODO
}
Object.defineProperty(obj,key,{
get:function(){
//将onDependencyUpdated这个函数传给Dep.target
Dep.target=onDependencyUpdated;
varvalue=computeFunc();
Dep.target=null;
},
set:function(){
//什么也不做,不需要设定计算属性的值
}
})
}
现在让我们回到之前设置的响应属性上:
functiondefineReactive(obj,key,val){
//所有的计算属性都依赖这个数组
vardeps=[];
Object.defineProperty(obj,key,{
get:function(){
//检查是否调用了计算属性,如果调用了,Department.target将等于一个onDependencyUpdated函数
if(Dep.target){
//把onDependencyUpdated函数push到deos中
deps.push(target);
}
returnval;
},
set:function(newValue){
val=newValue;
//通知所有的计算属性,告诉它们有个响应属性更新了
deps.forEach((changeFunction)=>{
changeFunction();
});
}
})
};
我们可以在计算属性定义的函数触发更新回调后更新onDependencyUpdated函数。
varonDependencyUpdated=function(){
//再次计算计算属性的值
varvalue=computeFunc();
updateCallback(value);
}
把它们整合到一起:
让我们重新访问我们的计算属性person.status:
person.age=22;
defineComputed(
person,
'status',
function(){
if(person.age>18){
return'adult';
}
},
function(newValue){
console.log("statushaschangedto",newValue)
}
});
console.log("Statusis",person.status);
总结
以上所述是小编给大家介绍的Vue.js中的computed工作原理,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对毛票票网站的支持!