咱们经过实现一个简单版的和Vue中computed具备相同功能的函数来了解computed是如何工做的。css
JS属性: JavaScript有一个特性是 Object.defineProperty ,它能作不少事,但我在这篇文章只专一于这个方法中的一个:html
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内部构建了一个能够将普通的对象转化为能够被观察的值( 响应属性 ),下面为你们展现一个简化版的如何添加响应属性的案例:vue
function defineReactive (obj, key, val) {
Object.defineProperty (obj, key, {
get: function () {
return val;
},
set: function (newValue) {
val = newValue;
}//欢迎加入全栈开发交流圈一块儿学习交流:864305860
})
};
// 建立一个对象
var person = {};
// 添加可响应的属性"age"和"country"
defineReactive (person, 'age', 25);
defineReactive (person, 'country', 'Brazil');
// 如今你能够随意使用person.age了
if (person.age < 18) {
return 'minor';
}//欢迎加入全栈开发交流圈一块儿学习交流:864305860
else {
return 'adult';
}
// 设置person.country的值
person.country = 'Russia';
复制代码
25 和 ‘Brazil' 仍是一个闭包内部的变量,只有当赋给它们新值的时候 val 才会改变。 person.country 并不拥有 'Brazil' 这个值,而是getter这个函数拥有 'Brazil' 这个值。 声明一个计算属性 让咱们建立一个定义计算属性的函数 defineComputed 。这个函数就跟你们平时使用computed时的同样。node
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 函数,它支持调用计算方法,但目前不须要它支持 updateCallbackwebpack
function defineComputed (obj, key, computeFunc, updateCallback) {
Object.defineProperty (obj, key, {
get: function () {
// 执行计算函数而且返回值
return computeFunc ();
},
set: function () {
// 什么也不作,不须要设定计算属性的值
}//欢迎加入全栈开发交流圈一块儿学习交流:864305860
})
}//帮助突破技术瓶颈,提高思惟能力
复制代码
这个函数有两个问题: 每次访问计算属性时都会执行一次计算函数 computeFunc () 它不知道何时更新 (即当咱们更新某个data中的属性,计算属性中也会更新这个data属性)web
// 我但愿最终函数执行后是这个效果:每当person.age更新值的时候,person.status也同步更新
person.age = 17;
// console: status 的值为 minor
person.age = 22;
// console: status 的值为 adult
复制代码
增长一个依赖项 让咱们增长一个全局变量 Dep :面试
var Dep = {
target: null
};
复制代码
这是一个依赖项,接着咱们用一个骚操做来更新 defineComputed 函数:数组
var onDependencyUpdated = function () {
// TODO
}
Object.defineProperty (obj, key, {
get: function () {
// 将onDependencyUpdated 这个函数传给Dep.target
Dep.target = onDependencyUpdated;
var value = computeFunc ();
Dep.target = null;
},//帮助突破技术瓶颈,提高思惟能力
set: function () {
// 什么也不作,不须要设定计算属性的值
}
})
}
复制代码
回到以前设置的响应属性上:bash
function defineReactive (obj, key, val) {
// 全部的计算属性都依赖这个数组
var deps = [];
Object.defineProperty (obj, key, {
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 ();
});//欢迎加入全栈开发交流圈一块儿学习交流:864305860
}//帮助突破技术瓶颈,提高思惟能力
})
};
复制代码
能够在计算属性定义的函数触发更新回调后更新 onDependencyUpdated 函数。闭包
var onDependencyUpdated = function () {
// 再次计算 计算属性的值
var value = computeFunc ();
updateCallback (value);
}
复制代码
把它们整合到一块儿,从新访问咱们的计算属性 person.status :
person.age = 22;
defineComputed (
person,
'status',
function () {
if (person.age > 18) {
return 'adult';
}//欢迎加入全栈开发交流圈一块儿学习交流:864305860
},//帮助突破技术瓶颈,提高思惟能力
function (newValue) {
console.log ("status has changed to", newValue)
}
});
console.log ("Status is ", person.status);
复制代码
结语
感谢您的观看,若有不足之处,欢迎批评指正。
本次给你们推荐一个免费的学习群,里面归纳移动应用网站开发,css,html,webpack,vue node angular以及面试资源等。 对web开发技术感兴趣的同窗,欢迎加入Q群:864305860,无论你是小白仍是大牛我都欢迎,还有大牛整理的一套高效率学习路线和教程与您免费分享,同时天天更新视频资料。 最后,祝你们早日学有所成,拿到满意offer,快速升职加薪,走上人生巅峰。