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 AutoScroller 函数类
May 29 Javascript
javascript 写类方式之三
Jul 05 Javascript
快速解决jquery之get缓存问题的最简单方法介绍
Dec 19 Javascript
JavaScript简单实现鼠标拖动选择功能
Mar 06 Javascript
通过$(this)使用jQuery包装后的方法或属性
May 18 Javascript
JS实现向表格中动态添加行的方法
Mar 30 Javascript
PHP捕捉异常中断的方法
Oct 24 Javascript
Easyui的组合框的取值与赋值
Oct 28 Javascript
node.js入门学习之url模块
Feb 25 Javascript
js实现随机点名系统(实例讲解)
Oct 18 Javascript
js与jQuery实现获取table中的数据并拼成json字符串操作示例
Jul 12 jQuery
vue修改对象的属性值后页面不重新渲染的实例
Aug 09 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 for 循环语句使用方法详细说明
2010/05/09 PHP
php 实现进制转换(二进制、八进制、十六进制)互相转换实现代码
2010/10/22 PHP
php简单实现短网址(短链)还原的方法(测试可用)
2016/05/09 PHP
Laravel 使用查询构造器配合原生sql语句查询的例子
2019/10/12 PHP
兼容IE与firefox火狐的回车事件(js与jquery)
2010/10/20 Javascript
Javascript和HTML5利用canvas构建Web五子棋游戏实现算法
2013/07/17 Javascript
Jquery获取元素的父容器对象示例代码
2014/02/10 Javascript
node.js中的favicon.ico请求问题处理
2014/12/15 Javascript
Javascript节点关系实例分析
2015/05/15 Javascript
使用postMesssage()实现跨域iframe页面间的信息传递方法
2016/03/29 Javascript
详解微信小程序开发之——wx.showToast(OBJECT)的使用
2017/01/18 Javascript
ES6中Array.copyWithin()函数的用法实例详解
2017/09/16 Javascript
JavaScript实现职责链模式概述
2018/01/25 Javascript
js中apply()和call()的区别与用法实例分析
2018/08/14 Javascript
创建Vue项目以及引入Iview的方法示例
2018/12/03 Javascript
JS/HTML5游戏常用算法之路径搜索算法 随机迷宫算法详解【普里姆算法】
2018/12/13 Javascript
在layui中对table中的数据进行判断(0、1)转换为提示信息的方法
2019/09/28 Javascript
js实现旋转木马轮播图效果
2020/01/10 Javascript
在博客园博文中添加自定义右键菜单的方法详解
2020/02/05 Javascript
简单了解three.js 着色器材质
2020/08/03 Javascript
[01:32]寻找你心中的那团火 DOTA2 TI9火焰传递活动今日开启
2019/05/16 DOTA
在Python中编写数据库模块的教程
2015/04/29 Python
python OpenCV学习笔记之绘制直方图的方法
2018/02/08 Python
Python控制Firefox方法总结
2019/06/03 Python
Python 读取用户指令和格式化打印实现解析
2019/09/02 Python
Python拆分大型CSV文件代码实例
2019/10/07 Python
解决Jupyter因卸载重装导致的问题修复
2020/04/10 Python
TensorFlow打印输出tensor的值
2020/04/19 Python
利用CSS3 动画 绘画 圆形动态时钟
2018/03/20 HTML / CSS
美国最大的宠物药店:1-800-PetMeds
2016/10/02 全球购物
英国莱斯特松木橡木家具网上商店:Choice Furniture Superstore
2019/07/05 全球购物
中班中秋节活动反思
2014/02/18 职场文书
党的群众路线教育实践活动个人对照检查材料(四风)
2014/11/05 职场文书
2014年实习班主任工作总结
2014/11/08 职场文书
2016秋季校长开学典礼致辞
2015/11/26 职场文书
安装Windows Server 2012 R2企业版操作系统并设置好相关参数
2022/04/29 Servers