深入解析Vue中的computed工作原理
我们通过实现一个简单版的和Vue中computed具有相同功能的函数来了解computed是如何工作的。
JS属性: JavaScript有一个特性是 Object.defineProperty ,它能做很多事,但我在这篇文章只专注于这个方法中的一个:
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内部构建了一个可以将普通的对象转化为可以被观察的值( 响应属性 ),下面为大家展示一个简化版的如何添加响应属性的案例:
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时的一样。
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
function defineComputed (obj, key, computeFunc, updateCallback) {
Object.defineProperty (obj, key, {
get: function () {
// 执行计算函数并且返回值
return computeFunc ();
},
set: function () {
// 什么也不做,不需要设定计算属性的值
}//欢迎加入全栈开发交流圈一起学习交流:864305860
})
}//帮助突破技术瓶颈,提升思维能力
这个函数有两个问题: 每次访问计算属性时都会执行一次计算函数 computeFunc () 它不知道什么时候更新 (即当我们更新某个data中的属性,计算属性中也会更新这个data属性)
// 我希望最终函数执行后是这个效果:每当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 () {
// 什么也不做,不需要设定计算属性的值
}
})
}
回到之前设置的响应属性上:
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);
结语
感谢您的观看,如有不足之处,欢迎批评指正。

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
-
上一篇
深入解析webpack 插件html-webpack-plugin
这个插件用来简化创建服务于 webpack bundle 的 HTML 文件,尤其是对于在文件名中包含了 hash 值,而这个值在每次编译的时候都发生变化的情况。你既可以让这个插件来帮助你自动生成 HTML 文件,也可以使用 lodash 模板加载生成的 bundles,或者自己加载这些 bundles。 Installation 使用 npm 安装这个插件 $ npm install html-webpack-plugin@2 --save-dev Basic Usage 这个插件可以帮助生成 HTML 文件,在 body 元素中,使用 script 来包含所有你的 webpack bundles,只需要在你的 webpack 配置文件中如下配置: var HtmlWebpackPlugin = require('html-webpack-plugin') var webpackConfig = { entry: 'index.js', output: { path: 'dist', filename: 'index_bundle.js' }, plugins: [new HtmlW...
-
下一篇
Google Java 代码规范
1. 简介 本文档用于Java编程语言的Google源代码编码标准的完整定义。Java源文件定义为Google风格。 于其他编程风格指南一样,所涉及的问题不止包含代码格式美化,还包括其他类型的约定或者编码标准。 但是本文档主要关注普遍遵循的严格规则,并避免提供意义不明的可执行建议(无论任何方式)。 1.1. 术语说明 本文件中除非另有说明: class包含用于表示普通类、枚举、接口或注解类型(@interface) 成员用于表示嵌套类、字段、方法或构造方法,也就是说除了初始设定和注释的顶级内容 注释总是实现注释,我们不使用短语“文档注释”,而是使用常规术语javadoc 其他术语说明会在整个文件中偶尔出现 译者注:嵌套类即内部类 1.2. 规范说明 本文档中的示例代码是非规范的。也就是说虽然示例是Google风格,但它们可能没有说明代码的唯一方式。 示例中的可选格式也不应作为规则强制执行。 2. 源文件基础 2.1. 文件名 源文件名包含顶级类并区分大小写(并且只有一个),加上.java扩展名。 2.2. 文件编码 源码文件编码必须是 UTF-8 译者注:因为不同操作系统默认的换行符不...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- Eclipse初始化配置,告别卡顿、闪退、编译时间过长
- CentOS关闭SELinux安全模块
- CentOS8编译安装MySQL8.0.19
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- SpringBoot2整合Thymeleaf,官方推荐html解决方案
- MySQL数据库在高并发下的优化方案
- SpringBoot2更换Tomcat为Jetty,小型站点的福音
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果