解析Vue.js中的computed工作原理
我们通过实现一个简单版的和Vue中computed具有相同功能的函数来了解computed是如何工作的。写的十分的全面细致,具有一定的参考价值,对此有需要的朋友可以参考学习下。如有不足之处,欢迎批评指正。
JS属性:
JavaScript有一个特性是 Object.defineProperty ,它能做很多事,但我在这篇文章只专注于这个方法中的一个:
var person = {};
Object.defineProperty (person, 'age', {
get: function () {
console.log ("Getting the age");
return 25;
}
});//欢迎加入前端全栈开发交流圈一起吹水聊天学习交流:864305860
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';
}//欢迎加入前端全栈开发交流圈一起吹水聊天学习交流:864305860
// 设置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 ();
},//欢迎加入前端全栈开发交流圈一起吹水聊天学习交流:864305860
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
}//欢迎加入前端全栈开发交流圈一起吹水聊天学习交流:864305860
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
}//面向1-3年前端人员
})
};
我们可以在计算属性定义的函数触发更新回调后更新 onDependencyUpdated 函数。
var onDependencyUpdated = function () {
// 再次计算 计算属性的值
var value = computeFunc ();
updateCallback (value);
}//欢迎加入前端全栈开发交流圈一起学习交流:864305860
把它们整合到一起:
让我们重新访问我们的计算属性 person.status :
person.age = 22;
defineComputed (
person,
'status',
function () {
if (person.age > 18) {
return 'adult';
}
},
function (newValue) {
console.log ("status has changed to", newValue)
}//欢迎加入前端全栈开发交流圈一起学习交流:864305860
});
console.log ("Status is ", person.status);
结语
感谢您的观看,如有不足之处,欢迎批评指正。
原文地址:https://segmentfault.com/a/1190000017356237
解析Vue.js中的computed工作原理的更多相关文章
- 深入解析Vue.js中v-bind v-model的使用和区别
v-model 指令在表单控件元素上创建双向数据绑定,所谓双向绑定,指的就是我们在js中的vue实例中的data与其渲染的dom元素上的内容保持一致,两者无论谁被改变,另一方也会相应的更新为相同的数据 ...
- vue.js中的computed和watch的区别
1.computed在调用时不需要加(),watch是不需要调用的2.computed如果属性没有发生改变时会从缓存中读取值,watch当属性发生改变时会接收到2个值:一个为新值,一个为旧值3.com ...
- 实例分析Vue.js中 computed和methods不同机制
在vue.js中,有methods和computed两种方式来动态当作方法来用的 1.首先最明显的不同 就是调用的时候,methods要加上() 2.我们可以使用 methods 来替代 comput ...
- vue.js 中 data, prop, computed, method,watch 介绍
vue.js 中 data, prop, computed, method,watch 介绍 data, prop, computed, method 的区别 类型 加载顺序 加载时间 写法 作用 备 ...
- Vue.js双向绑定的实现原理和模板引擎实现原理(##########################################)
Vue.js双向绑定的实现原理 解析 神奇的 Object.defineProperty 这个方法了不起啊..vue.js和avalon.js 都是通过它实现双向绑定的..而且Object.obser ...
- vue.js 中双向绑定的实现---初级
1. 1 我们看到的变量,其实都不是独立的,它们都是windows对象上的属性 <!DOCTYPE html> <html lang="en"> <h ...
- vue.js中,input和textarea上的v-model指令到底做了什么?
v-model是 vue.js 中用于在表单表单元素上创建双向数据绑定,它的本质只是一个语法糖,在单向数据绑定的基础上,增加了监听用户输入事件并更新数据的功能: 对,它本质上只是一个语法糖,但到底是一 ...
- Vue.js 计算属性(computed)
Vue.js 计算属性(computed) 如果在模板中使用一些复杂的表达式,会让模板显得过于繁重,且后期难以维护.对此,vue.js 提供了计算属性(computed),你可以把这些复杂的表达式写到 ...
- angular.js和vue.js中实现函数去抖(debounce)
问题描述 搜索输入框中,只当用户停止输入后,才进行后续的操作,比如发起Http请求等. 学过电子电路的同学应该知道按键防抖.原理是一样的:就是说当调用动作n毫秒后,才会执行该动作,若在这n毫秒内又调用 ...
随机推荐
- vue教程6-图表
引入 cnpm install echarts --save #在vue项目目录下安装echarts 静态折线图 linechart.js import echarts from 'echarts' ...
- CC38:第k个数
题目 有一些数的素因子只有3.5.7,请设计一个算法,找出其中的第k个数. 给定一个数int k,请返回第k个数.保证k小于等于100. 测试样例: 3 返回:7 解法 主要就是在于isPrime这个 ...
- c# Array或List有个很实用的ForEach方法,可以直接传入一个方法对集合中元素操作
using System; using System.Collections.Generic; namespace demo { class Program { static void Main(st ...
- Codeforces Round #562 (Div. 2) A.Circle Metro
链接:https://codeforces.com/contest/1169/problem/A 题意: The circle line of the Roflanpolis subway has n ...
- Function.prototype.apply.call
我们先从一道简单的题目开始,前几天在git上看到的: 定义log方法,它可以代理console.log的方法.log(1,2,3) => 1 2 3 通常,你的答案会是这样的: functi ...
- pytorch 0.3 win7 安装
pytorch 0.3 win7 安装 参考这个文章:https://github.com/peterjc123/pytorch-scripts 首先安装 conda 这个链接下载: python 3 ...
- Oracle创建用户、表(1)
Oracle创建用户.表(1) 1. 连接 C:\Users\LEI>sqlplus / as sysdba SQL*Plus: Release 12.1.0.2.0 Production on ...
- Android笔记--LayoutInflator源码和使用分析
LayoutInflator源码分析 获取LayoutInflator对象 获取LayoutInflator的方式有两种: 使用LayoutInflator.from(Context context) ...
- socket tcp使用recv接收数据时,返回errno错误代码88
原因:就是recv函数的第一个参数不是可用的,也就是第一个参数不是建立连接时返回的文件描述符. 解决方法:xxx
- 【虚拟机-远程连接】Azure Linux 虚拟机常见导致无法远程的操作
对Azure虚拟机的一些操作可能会导致无法远程连接,本文罗列了以下导致不能远程连接的场景: 场景1 - 在虚拟机配置IP地址或MAC地址 场景2 - 错误地修改服务的配置文件 场景3 - 误设置防火墙 ...