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 相关文章推荐
COM中获取JavaScript数组大小的代码
Nov 22 Javascript
读取input:file的路径并显示本地图片的方法
Sep 23 Javascript
基于jQuery滑动杆实现购买日期选择效果
Sep 15 Javascript
简单实现JS对dom操作封装
Dec 02 Javascript
javascript实现拖放效果
Dec 16 Javascript
AngularJS 自定义指令详解及示例代码
Aug 17 Javascript
使用 Vue 绑定单个或多个 Class 名的实例代码
Jan 08 Javascript
基于IView中on-change属性的使用详解
Mar 15 Javascript
vue插槽slot的理解和使用方法
Apr 03 Javascript
亲自动手实现vue日历控件
Jun 26 Javascript
解决Vue在Tomcat8下部署页面不加载的问题
Nov 12 Javascript
Vue 打包的静态文件不能直接运行的原因及解决办法
Nov 19 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
防止MySQL注入或HTML表单滥用的PHP程序
2009/01/21 PHP
ThinkPHP中使用ajax接收json数据的方法
2014/12/18 PHP
Auntion-TableSort国人写的一个javascript表格排序的东西
2007/11/12 Javascript
JavaScript 全角转半角部分
2009/10/28 Javascript
jquery xMarquee实现文字水平无缝滚动效果
2014/04/29 Javascript
js全选实现和判断是否有复选框选中的方法
2015/02/17 Javascript
前端实现文件的断点续传(前端文件提交+后端PHP文件接收)
2016/11/04 Javascript
js实现音频控制进度条功能
2017/04/01 Javascript
AngularJS双向绑定和依赖反转实例详解
2017/04/15 Javascript
JS库之wow.js使用方法
2017/09/14 Javascript
jquery select插件异步实时搜索实例代码
2017/10/20 jQuery
VueJs监听window.resize方法示例
2018/01/17 Javascript
详解mpvue开发小程序小总结
2018/07/25 Javascript
react build 后打包发布总结
2018/08/24 Javascript
基于Vue-Cli 打包自动生成/抽离相关配置文件的实现方法
2018/12/09 Javascript
Ant Design Vue 添加区分中英文的长度校验功能
2020/01/21 Javascript
React中Ref 的使用方法详解
2020/04/28 Javascript
Python内存读写操作示例
2018/07/18 Python
浅谈Python在pycharm中的调试(debug)
2018/11/29 Python
python实现五子棋小程序
2019/06/18 Python
python爬虫 爬取58同城上所有城市的租房信息详解
2019/07/30 Python
如何基于matlab相机标定导出xml文件
2020/11/02 Python
python gui开发——制作抖音无水印视频下载工具(附源码)
2021/02/07 Python
Python制作运行进度条的实现效果(代码运行不无聊)
2021/02/24 Python
一款利用html5和css3实现的3D滚动特效的教程
2015/01/04 HTML / CSS
波兰办公用品和学校用品在线商店:Dlabiura24.pl
2020/11/18 全球购物
JVM是一个编译程序还是解释程序
2012/09/11 面试题
档案接收函
2014/01/13 职场文书
银行工作检查书范文
2014/01/31 职场文书
社团活动总结范文
2014/04/26 职场文书
公司委托书怎么写
2014/08/02 职场文书
运动会演讲稿50字
2014/08/25 职场文书
员工试用期自我鉴定范文
2014/09/15 职场文书
个人党性分析材料
2014/12/19 职场文书
小型企业的绩效考核制度模板
2019/11/21 职场文书
Python first-order-model实现让照片动起来
2022/06/25 Python