作者从 Java 与 C# 中经典的 Getters/Setters 引入,讨论了 Vue.js 中从组件渲染函数、数据的 Getter、Setter 劫持、监听器的控制以及重渲染触发整个生命流程。
原文链接:Understanding Vue.js Reactivity in Depth with Object.defineProperty()
引子
本人是Java背景,许多年前刚接触JavaScript时有点怪怪的,因为它没有 getters
和 setters
。随着时间的推移,我开始喜欢上这个缺失的特性,因为相比Java大量的 getter
和 setter
,它让代码更简洁。例如,我们看看下面的Java代码:
|
|
JavaScript开发人员永远不会这样做,相反他们会这样:
|
|
这要简洁的多。通常简洁更好,不是吗?
的确如此,但有时我想获取一些可以被修改的属性,但我不用知道这些属性是什么。例如,我们在Java代码中扩展一个新的方法 getFullName()
:
|
|
在上面例子中, fullName
是一个计算过的属性,它不是私有属性,但总能返回正确的结果。
C# 和隐式的 getter/setters
我们来看看 C# 特性之一:隐式的 getters/setters,我真的很喜欢它。在 C# 中,如果需要,你可以定义 getters/setters,但是并不用这样做,但是如果你决定要这么做,调用者就不必调用函数。调用者只需要直接访问属性,getter/setter 会自动在钩子函数中运行:
|
|
我觉得这很酷…
现在,如果我想在JavaScript中实现类似的功能,我会浪费很多时间,比如:
|
|
它会打印出:
|
|
但使用 setXXX(value)
的方式并不够’javascripty’(是个玩笑啦)。
下面的方式可以解决这个问题:
|
|
现在我们回到被计算过的 getter。你可以设置 first 或 last
name,并简单的合并它们的值:
|
|
这的确更方便,但我还是不喜欢它,因为我们要定义一个叫“getxxx()”的方法,这也不够’javascripty’。许多年来,我一直在思考如何更好的使用 JavaScript。
然后 Vue 出现了
在我的Youtube频道,很多和Vue教程有关的视频都讲到,我习惯响应式开发,在更早的Angular1时代,我们叫它:数据绑定(Data Binding)。它看起来很简单。你只需要在Vue实例的 data()
块中定义一些数据,并绑定到HTML:
|
|
|
|
显然它会在用户界面打印出 “Hello world!”。
现在,如果你改变“greeting”的值,Vue引擎会对此作出反应并相应地更新视图。
|
|
很长一段时间我都在想,它是如何工作的?当某个对象的属性发生变化时会触发某个事件?或者Vue不停的调用 setInterval
去检查是否更新?
通过阅读Vue官方文档,我才知道,改变一个对象属性将隐式调用getter/setter,再次通知观察者,然后触发重新渲染,如下图,这个例子来自官方的vue.js文档:
但我还想知道:
怎么让数据自带
getter/setters
?这些隐式调用内部是怎样的?
第一个问题很简单:Vue为我们准备好了一切。当你添加新数据,Vue将会通过其属性为其添加 getter/setters
。但是我让 foo.bar = 3?
会发生什么?
这个问题的答案出现在我和SVG & Vue专家Sarah Drasner的Twitter对话中:
Timo:
foo.bar=value;
是怎么做到实时响应的?
Sarah: 这个问题很难在Twitter说清楚,可以看这篇文章
Timo: 但这篇文章并没有解释上面提到的问题。
Timo: 它们就像:分配一个值->调用setter->通知观察者,不理解为什么在不使用setInterval和Event的情况下,setter/getter就存在了。
Sarah: 我的理解是:你获取的所有数据都在Vue实例data{}中被代理了。
显然,她也是参考的官方文档,之前我也读过,所以我开始阅读Vue源码,以便更好的理解发生了什么。过了一会我想起在官方文档看到一个叫 Object.defineProperty()
的方法,我找到它,如下:
|
|
所以答案一直存在于文档中:
把一个普通 JavaScript 对象传给 Vue 实例的 data 选项,Vue 将遍历此对象所有的属性,并使用 Object.defineProperty 把这些属性全部转为 getter/setter。Object.defineProperty 是仅 ES5 支持,且无法 shim 的特性,这也就是为什么 Vue 不支持 IE8 以及更低版本浏览器的原因。
我只想简单的了解 Object.defineProperty()
做了什么,所以我用一个例子简单的给你讲解一下:
|
|
还记得文章开头C#的隐式 getter
吗?它们看起来很类似,但ES5才开始支持。你需要做的是使用 Object.defineProperty()
定义现有对象,以及何时获取这个属性,这个getter被称为响应式——这实际上就是Vue在你添加新数据时背后所做的事。
Object.defineProperty()能让Vue变的更简化吗?
学完这一切,我一直在想,Object.defineProperty()
是否能让Vue变的更简化?现今越来越多的新术语,是不是真的有必要把事情变得过于复杂,变的让初学者难以理解(Redux也是同样):
Mutator - 或许你在说(隐式)setter
Getters - 为什么不用
Object.defineProperty()
替换成(隐式)
getterstore.commit() - 为什么不简化成
foo = bar
,而是store.commit("setFoo", bar);
?
你是怎么认为的?Vuex必须是复杂的还是可以像 Object.defineProperty()
一样简单?
本文译者:余震(Freak)
译文出处:Rockjins Blog
版权声明:本博客所有文章除特别声明外,均采用 CC BY-NC-SA 3.0 CN许可协议。转载请注明出处!