vue使用computed有参数_Vue深入浅出computed(进阶必看系列)

简介

大家好,我是六六。在我们开发当中,当然少不了使用computed计算属性,都知道结果会被缓存起来,那是怎么做到的呢。当然了,在面试中也经常会问到与watch到底有什么不同,那儿接下来,我们将走进computed的内部,详细的去了解一下。

目录

你知道的computed特性

computed原理是什么

computed原理具体实现

详说整个computed过程

面试题与扩展

总结

1.你知道的computed特性:

计算属性在使用的时候,要当做普通属性使用就好,不需要加()

只要计算属性这个function内部所用到的data中的数据发生了变化,就会立即重新计算这个计算属性的值

计算属性的求值结果,会被缓存起来,方便下次继续使用;如果计算属性方法中,所依赖的任何数据,都没有发生过变化,则不会重新对计算属性求值

可以为函数或者对象

2.computed原理是什么:

学习中最常见听到的一句话就是,computed就是一个特殊的getter方法。在代理函数可以结合watcher实现缓存与收集依赖。

计算属性具有缓存性,如何知道计算属性的返回值发生变化呢?

这其实就是结合了watcher的dirty属性来分辨的,当dirty为true时,说明需要重新计算,当为false时,计算属性没有改变,不需要重新计算,直接读取缓存值就好。

模拟一下计算属性内容发生改变后:

计算属性的watcher和组件内的watcher都会得到通知

计算属性的watcher将自己的属性dirty设置为true

下次读取计算属性时,因为dirty为true重新计算一次值

组件watcher得到通知,从而执行render函数进行重新渲染

3.computed原理具体实现:

3.1 initComputed初始化

const computedWatcherOptions={lazy:true}

function initComputed(vm, computed) {

const watchers = vm._computedWatchers = Object.create(null)

const isSSR = isServerRendering()

for (const key in computed) {

// userDef我们定义的计算属性

const userDef = computed[key]

// 获取getter

const getter = typeof userDef === 'function' ? userDef : userDef.get

// 非SSR环境

if (!isSSR) {

// 创建watcher实例

watchers[key] = new Watcher(vm, getter || noop, noop, computedWatcherOptions)

}

if (!(key in vm)) {

defineComputed(vm, key, userDef)

}

}

}

复制代码

具体讲解:

initComputed函数接受两个参数:vm实例和computed对象

声明了一个变量watchers,并保存在vm._computedWatchers

声明变量isSSR用于判断是否在SSR环境

使用for..in循环computed对象,以此初始化每个计算属性

用getter保存计算结果的值

创建watcher实例

判断计算属性的值是否已经在vm实例上定义了,如果没有,执行defineComputed函数

到这里,我们就明白了,最后我们会执行defineComputed函数,对每个计算属性进行定义和初始化。下面我们来看看这个函数。

3.2 defineComputed定义计算属性

const sharePropertyDefinition={

enumerable:true,

configurable:true,

get:noop,

set:noop

}

function defineComputed(target,key,userDef){

// 判断环境

const shouldCache=!isServerRendering()

// 设置的为函数

if(typeof userDef==='function'){

sharePropertyDefinition.get=shouldCache?createComputedGetter(key):userDef

sharePropertyDefinition.set=noop

}

// 设置的为对象

else{

sharePropertyDefinition.get=userDef.get?shouldCache&&userDef.cache!=false?createComputedGetter(key):userDef.get:noop

sharePropertyDefinition.set=userDef.set?userDef.set:noop

}

Object.defineProperty(target,key,sharePropertyDefinition)

}

复制代码

具体讲解:

首先定义sharePropertyDefinition变量,用于配合Object.defineProperty使用。

函数defineComputed接受target,key,userDef三个参数

使用shouldCache变量确认是否在SSR环境

判断userDef是否为函数,因为我们知道我们传入的computed支持函数或者对象

如果是函数,判断shouldCache,为true时执行createComputedGetter函数,并赋值给 sharePropertyDefinition.get

如果不是函数,是否写了get函数,判断shouldCache,为true时执行createComputedGetter函数,并赋值给 sharePropertyDefinition.get

在判断用户是否写了set函数,写了就赋值给sharePropertyDefinition,noop为空函数。

在最后,执行Object.defineProperty向实例挂载属性

所以,计算属性的缓存和响应式主要在于是否将getter方法设置为createComputedGetter。因为最终挂载到get方法的就是createComputedGetter函数。

3.3createComputedGetter缓存与响应式的关键

function createComputedGetter (key) {

return function computedGetter () {

const watcher = this._computedWatchers && this._computedWatchers[key]

if (watcher) {

if (watcher.dirty) {

watcher.evaluate()

}

if (Dep.target) {

watcher.depend()

}

return watcher.value

}

}

}

复制代码

具体讲解:

在initComputed函数中我们定义了_computedWatchers属性,通过_computedWatchers[key]拿到我们定义的watcher,所以变量watcher就是每个watcher的实例

判断watcher.dirty值是否为真,为真就重新计算一下,也就是执行watcher.evaluate()

判断Dep.target的值,如果有,就执行 watcher.depend(),最后返回watcher的value值。

代码是非常简单的,但是理解起来是需要配合watcher和dep的,如果不了解可以参考我这篇文章:

深入浅出Vue变化侦测

3.4 与watcher密不可分

class Watcher{

constructor(vm,expOrFn,cb,options){

// 无关代码

if(options){

this.lazy=!!options.lazy

}

this.dirty = this.lazy

}

evaluate () {

this.value = this.get()

this.dirty = false

}

/**

* Depend on all deps collected by this watcher.

*/

depend () {

let i = this.deps.length

while (i--) {

this.deps[i].depend()

}

}

}

复制代码

evaluate方法:就是从watcher重新获取一次表达式的值

depend方法:

this.deps[i]就是计算属性所依赖的状态

调用depend方法可以将组件的watcher实例添加到dep实例中,意思就是计算属性所依赖的状态改变也会通知组件,更具体说,就是组件watcher也会观察计算属性所依赖的状态。(组件watcher是如何拿到的呢)

4.详说整个computed过程:

使用watcher读取计算属性

读取计算属性函数中的数据,定义响应式时,get读取的就是watcher.value

计算属性和组件watcher同时观察数据的变化

当数据改变后,计算属性和组件watcher都会收到通知

组件watcher会重新渲染组件

计算属性watcher因为数据改变,dirty属性为true,将重新计算

计算属性计算的结果用于本次渲染,并缓存起来

5.面试题:watch和computed的区别是什么?

其实我觉得这两个作用是完全不一样,不知道为什么总拿来比较。

watch是一种行为,在状态改变之后需要做什么。

computed就是一种状态,也可以说多种状态初始化后的结果。

我认为把,computed与filter作为比较不是更好一些吗?都是用来初始化状态用的。

computed更适用于大量数据计算的结果,并且反复使用,而且不常更新。因为有缓存,大大提升性能。

filter适用于少量数据进行初始化处理,计算量不能太大,因为每次渲染都会计算,并且可以频繁更新。

6.总结

一开始学这个知识点确实很懵,一个知识点看了很多遍,到最后才领悟过来,不过也有很多一知半解的地方,所以每天还是要继续努力。

关于找一找教程网

本站文章仅代表作者观点,不代表本站立场,所有文章非营利性免费分享。

本站提供了软件编程、网站开发技术、服务器运维、人工智能等等IT技术文章,希望广大程序员努力学习,让我们用科技改变世界。

[Vue深入浅出computed(进阶必看系列)]http://www.zyiz.net/tech/detail-131176.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值