Vue.js中的computed工作原理

JS属性

JavaScript有一个特性是 Object.defineProperty,它能做很多事,但我在这文章只专注于这个方法中的一个

rush:js;"> var person = {}; Object.defineProperty (person,'age',{ get: function () { console.log ("Getting the age"); return 25; } }); console.log ("The age is ",person.age); // Prints: // // Getting the age // The age is 25

(Obeject.defineProperty是Object的一个方法,第一个参数是对象名称,第二个参数是要设置的属性名,第三个参数是一个对象,它可以设置这个属性是否可修改、可写等,而这篇文章主要使用的是Obeject.defineProperty的访问器属性,感兴趣的朋友可以自行google或者查看Js高及程序设计)

尽管 person.age 看起来像是访问了对象的一个属性,但其实在内部我们是运行了一个函数

一个基本可响应的Vue.js

Vue.js内部构建了一个可以将普通的对象转化为可以被观察的值( 响应属性 ),下面为大家展示一个简化版的如何添加响应属性的案例:

rush:js;"> function defineReactive (obj,key,val) { Object.defineProperty (obj,{ get: function () { return val; },set: function (newValue) { val = newValue; } }) }; // 创建一个对象 var person = {}; // 添加可响应的属性"age"和"country" defineReactive (person,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时的一样。

rush:js;"> defineComputed ( person,// 计算属性就声明在这个对象上 'status',// 计算属性名称 function () { // 实际返回计算属性值的函数 console.log ("status getter called") if (person.age < 18) { return 'minor'; } else { return 'adult'; } },function (newValue) { // 当计算属性值更新时调用函数 console.log ("status has changed to",newValue) } }); // 我们可以像使用一般的属性一样使用计算属性 console.log ("The person's status is: ",person.status);

让我们写一个简单的 defineComputed 函数,它支持调用计算方法,但目前不需要它支持 updateCallback 。

rush:js;"> function defineComputed (obj,computeFunc,updateCallback) { Object.defineProperty (obj,{ get: function () { // 执行计算函数并且返回值 return computeFunc (); },set: function () { // 什么也不做,不需要设定计算属性的值 } }) }

这个函数有两个问题:

每次访问计算属性时都会执行一次计算函数 computeFunc ()

它不知道什么时候更新 (即当我们更新某个data中的属性,计算属性中也会更新这个data属性

rush:js;"> // 我希望最终函数执行后是这个效果:每当person.age更新值的时候,person.status也同步更新 person.age = 17; // console: status 的值为 minor person.age = 22; // console: status 的值为 adult

增加一个依赖项

让我们增加一个全局变量 Dep :

rush:js;"> var Dep = { target: null };

这是一个依赖项,接着我们用一个骚操作来更新 defineComputed 函数

rush:js;"> function defineComputed (obj,updateCallback) { var onDependencyUpdated = function () { // Todo } Object.defineProperty (obj,{ get: function () { // 将onDependencyUpdated 这个函数传给Dep.target Dep.target = onDependencyUpdated; var value = computeFunc (); Dep.target = null; },set: function () { // 什么也不做,不需要设定计算属性的值 } }) }

现在让我们回到之前设置的响应属性上:

Object.defineProperty (obj,{
get: function () {
// 检查是否调用了计算属性,如果调用了,Department.target将等于一个onDependencyUpdated函数
if (Dep.target) {
// 把onDependencyUpdated函数push到deos中
deps.push (target);
}

return val;
},set: function (newValue) {
val = newValue;

// 通知所有的计算属性,告诉它们有个响应属性更新了
deps.forEach ((changeFunction) => {
changeFunction ();
});
}
})
};

我们可以在计算属性定义的函数触发更新回调后更新 onDependencyUpdated 函数

rush:js;"> var onDependencyUpdated = function () { // 再次计算 计算属性的值 var value = computeFunc (); updateCallback (value); }

把它们整合到一起:

让我们重新访问我们的计算属性 person.status :

18) { return 'adult'; } },function (newValue) { console.log ("status has changed to",newValue) } }); console.log ("Status is ",person.status);

总结

以上所述是小编给大家介绍的Vue.js中的computed工作原理。编程之家 jb51.cc 收集整理的教程希望能对你有所帮助,如果觉得编程之家不错,可分享给好友!感谢支持

相关文章

可以通过min-width属性来设置el-table-column的最小宽度。以...
yarn dev,当文件变动后,会自动重启。 yanr start不会自动重...
ref 用于创建一个对值的响应式引用。这个值可以是原始值(如...
通过修改 getWK005 函数来实现这一点。这里的 query 参数就是...
&lt;el-form-item label=&quot;入库类型&quot; ...
API 变动 样式类名变化: 一些组件的样式类名有所变动,可能需...