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 判断浏览器类型及版本
Feb 21 Javascript
JavaScript 学习笔记(十一)
Jan 19 Javascript
Jquery Ajax学习实例6 向WebService发出请求,返回DataSet(XML) 异步调用
Mar 18 Javascript
使用Jquery Aajx访问WCF服务(GET、POST、PUT、DELETE)
Mar 16 Javascript
jquery mobile实现拨打电话功能的几种方法
Aug 05 Javascript
javascript学习笔记(五)原型和原型链详解
Oct 08 Javascript
js图片轮播特效代码分享
Sep 07 Javascript
jquery实现ajax提交表单信息的简单方法(推荐)
Aug 24 Javascript
jQuery实现复选框的全选和反选
Feb 02 Javascript
Vue + Webpack + Vue-loader学习教程之相关配置篇
Mar 14 Javascript
JavaScript实现简单的星星评分效果
May 18 Javascript
js模拟实现百度搜索
Jun 28 Javascript
解决在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中的cookie
2006/11/26 PHP
PHP垃圾回收机制简单说明
2010/07/22 PHP
php实现利用phpexcel导出数据
2013/08/24 PHP
浅谈php冒泡排序
2014/12/30 PHP
Ajax中的JSON格式与php传输过程全面解析
2017/11/14 PHP
Laravel中9个不经常用的小技巧汇总
2019/04/16 PHP
Laravel 关联模型-关联新增和关联更新的方法
2019/10/10 PHP
js实现图片放大缩小功能后进行复杂排序的方法
2012/11/08 Javascript
js简易namespace管理器 实例代码
2013/06/21 Javascript
js用闭包遍历树状数组的方法
2014/03/19 Javascript
jQuery中toggleClass()方法用法实例
2015/01/05 Javascript
Bootstrap图片轮播组件使用实例解析
2016/06/30 Javascript
JS日程管理插件FullCalendar中文说明文档
2017/02/06 Javascript
Angularjs 实现移动端在线测评效果(推荐)
2017/04/05 Javascript
vue 打包后的文件部署到express服务器上的方法
2017/08/09 Javascript
vue环境搭建简单教程
2017/11/07 Javascript
浅谈基于Vue.js的移动组件库cube-ui
2017/12/20 Javascript
Angular 开发学习之Angular CLI的安装使用
2017/12/31 Javascript
Vue 组件传值几种常用方法【总结】
2018/05/28 Javascript
Vue中的基础过渡动画及实现原理解析
2018/12/04 Javascript
VUE简单的定时器实时刷新的实现方法
2019/01/20 Javascript
vue请求服务器数据后绑定不上的解决方法
2019/10/30 Javascript
js实现滑动进度条效果
2020/08/21 Javascript
JavaScript交换变量常用4种方法解析
2020/09/02 Javascript
Python编程之列表操作实例详解【创建、使用、更新、删除】
2017/07/22 Python
解决Mac安装scrapy失败的问题
2018/06/13 Python
Django中提示消息messages的设置方式
2019/11/15 Python
谈一谈数组拼接tf.concat()和np.concatenate()的区别
2020/02/07 Python
使用python-Jenkins批量创建及修改jobs操作
2020/05/12 Python
英国最全面的橄榄球联盟门票网站:Live Rugby Tickets
2018/10/06 全球购物
教育系毕业生中文求职信范文
2013/10/06 职场文书
学校运动会广播稿
2014/10/11 职场文书
民主评议党员个人总结
2015/02/13 职场文书
Python 使用dict实现switch的操作
2021/04/07 Python
Pytorch中Softmax与LogSigmoid的对比分析
2021/06/05 Python
JS实现九宫格拼图游戏
2022/06/28 Javascript