Vue.js中的computed工作原理


Posted in Javascript onMarch 22, 2018

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;
  }
 })
};
// 创建一个对象
var person = {};
// 添加可响应的属性"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 ("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 () {
   // 什么也不做,不需要设定计算属性的值
  }
 })
}

这个函数有两个问题:

每次访问计算属性时都会执行一次计算函数 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 函数:

function defineComputed (obj, key, computeFunc, updateCallback) {
 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 ();
   });
  }
 })
};

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

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

把它们整合到一起:

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

person.age = 22;
defineComputed (
 person,
 'status',
 function () {
  if (person.age > 18) {
   return 'adult';
  }
 },
 function (newValue) {
  console.log ("status has changed to", newValue)
 }
});
console.log ("Status is ", person.status);

总结

以上所述是小编给大家介绍的Vue.js中的computed工作原理,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Javascript 相关文章推荐
用javascript将数据库中的TEXT类型数据动态赋值到TEXTAREA中
Apr 20 Javascript
javascript中动态加载js文件多种解决办法总结
Nov 15 Javascript
JavaScript中自定义事件用法分析
Dec 23 Javascript
原生js实现淘宝购物车功能
Jun 23 Javascript
详解vue.js之绑定class和style的示例代码
Aug 24 Javascript
解决vue数组中对象属性变化页面不渲染问题
Aug 09 Javascript
React项目动态设置title标题的方法示例
Sep 26 Javascript
layui table去掉右侧滑动条的实现方法
Sep 05 Javascript
JS桶排序的简单理解与实现方法示例
Nov 25 Javascript
解决VUE项目使用Element-ui 下拉组件的验证失效问题
Nov 07 Javascript
JavaScript Html实现移动端红包雨功能页面
Jan 10 Javascript
VUE解决跨域问题Access to XMLHttpRequest at
May 06 Vue.js
解决在Bootstrap模糊框中使用WebUploader的问题
Mar 22 #Javascript
JS中的事件委托实例浅析
Mar 22 #Javascript
jquery的 filter()方法使用教程
Mar 22 #jQuery
p5.js实现斐波那契螺旋的示例代码
Mar 22 #Javascript
基于JavaScript实现幸运抽奖页面
Jul 05 #Javascript
Vue封装一个简单轻量的上传文件组件的示例
Mar 21 #Javascript
基于vue-video-player自定义播放器的方法
Mar 21 #Javascript
You might like
PHP 中文乱码解决办法总结分析
2009/07/30 PHP
php使用Jpgraph创建折线图效果示例
2017/02/15 PHP
php获取linux命令结果的实例
2017/03/13 PHP
PHP 进度条函数的简单实例
2017/09/19 PHP
页面版文本框智能提示JS代码
2009/11/20 Javascript
JQuery DataTable删除行后的页面更新利用Ajax解决
2013/05/17 Javascript
JavaScript中的关键字&quot;VAR&quot;使用详解 分享
2013/07/31 Javascript
利用JavaScript实现新闻滚动效果(实例代码)
2013/11/27 Javascript
详解基于webpack搭建react运行环境
2017/06/01 Javascript
js弹性势能动画之抛物线运动实例详解
2017/07/27 Javascript
vue 下列表侧滑操作实例代码详解
2018/07/24 Javascript
Element-ui之ElScrollBar组件滚动条的使用方法
2018/09/14 Javascript
js删除对象/数组中null、undefined、空对象及空数组方法示例
2018/11/14 Javascript
jQuery实现每日秒杀商品倒计时功能
2019/09/06 jQuery
layui问题之模拟table表格中的选中按钮选中事件的方法
2019/09/20 Javascript
vue自定义指令实现仅支持输入数字和浮点型的示例
2019/10/30 Javascript
[06:53]DOTA2每周TOP10 精彩击杀集锦vol.3
2014/06/25 DOTA
Python模拟鼠标点击实现方法(将通过实例自动化模拟在360浏览器中自动搜索python)
2017/08/23 Python
对python过滤器和lambda函数的用法详解
2019/01/21 Python
python实现将字符串中的数字提取出来然后求和
2020/04/02 Python
使用python实现时间序列白噪声检验方式
2020/06/03 Python
python适合做数据挖掘吗
2020/06/16 Python
结束运行python的方法
2020/06/16 Python
“型”走纽约上东区:Sam Edelman
2017/04/02 全球购物
美国照明、家居装饰和家具购物网站:Bellacor
2017/09/20 全球购物
优秀员工自荐书范文
2013/12/08 职场文书
七一表彰活动方案
2014/01/18 职场文书
让世界充满爱演讲稿
2014/05/24 职场文书
十佳标兵事迹材料
2014/08/18 职场文书
关于青春的演讲稿500字
2014/08/22 职场文书
网络工程专业大学生求职信
2014/10/01 职场文书
党小组意见范文
2015/06/08 职场文书
签字仪式主持词
2015/07/03 职场文书
汽车修理厂管理制度
2015/08/05 职场文书
MySQL之select、distinct、limit的使用
2021/11/11 MySQL
CentOS7环境下MySQL8常用命令小结
2022/06/10 Servers