这篇博客我们来讲下可响应对象的第二种方法,defineProperty。
尽管来说这个东西有众多的缺陷,但毕竟是非常有一席之地的一个东西,所以我们现在还是要比较深入的了解它一下。
首先这个 defineProperty 它的作用是什么?
就如它的名字所说的一样,它可以帮助我们来定义一个属性,只不过它定义出来的属性,不是普通的属性,是一个可以被监控,可以被监听的一个状态。
我们先来了解一下它的基本的语法,从最简单的开始说起。
首先,我们定义一个 json:
那么这个 json 是干什么的呢?其实它才是我们真正的那个数据。
然后在接下来,我们需要调用 Object.definProperty,在它里面,需要三个参数:
第一个参数,你需要告诉它,你要给哪个对象增加一个属性。
第二个参数,那个属性的名字。
比如我们给它加一个 a:
第三个参数则是一个对象,它里面可以放一些选项,你所有的操作,都是在这里面来规定的。
比如,你想怎么控制,能不能改,能不能删?还是怎么样,都是在这里面来做的。
而它里面,有 2 个最有用的东西,一个叫 get,一个叫 set:
这里顺便一说,defineProperty 的这个 get 和 set,它只是名字叫 get 和 set,跟我们上篇博客讲的访问器是两码事。
访问器的 get 和 set 后面是有名字的:
get xxx() { ... }
set xxx() { ... }
而 defineProperty 是这样写的:
get() { ... }
set() { ... }
defineProperty 的这个不是访问器,它就只是一个叫 get 或者 set 的方法。
这里大家要分清楚,不要搞混了。
然后 defineProperty 里面的 get 和 set,这两个东西的作用,和访问器几乎是一模一样的。什么作用呢?
就是我可以在读取或者设置的时候,拦截这些操作。
那么现在我们就来做的看下,我们先看看 json 里面有没有 a:
可以看到,是有的。
注意,这个 a 哪来的,我们并没有给 json 加啊?
其实是 defineProperty 它加上的,因为它就是用来添加属性的,并且它调用的就是那个 get。
set 也是一样的,从这个角度上来说,defineProperty 可以跟访问器的 get、set 一样来玩。
然后,我们现在希望有一个真实的数据,它是能变的,如果我们在 json 里面又加了一个 a 会怎么样呢?
我们来试试:
并且我们在 get 里面 return 的是 json.a,同时 set 里面也是 json.a = val:
这个时候,当我们去访问 a 或者去赋值 a 的时候:
可以看到,和之前的访问器一样,也出现无限死循环了。
所以名字得岔开,这个并不是某个特例。
所以我们需要加个下划线 _a:
这个时候,我们访问或者赋值的时候,就执行了 get 或者 set 了。
当然,还有个小事,这里顺便说一下。
我们的这个 json,表面上看起来,它是只有一个 _a 的:
但是如果你把它展开,你会发现,它里面还有个 get a 和 set a。
所以我们的这个 defineProperty,其实它的一个结果,是可以直接在 F12 里面能够看到的。
不知道大家有没有注意过,我们在使用某个框架的时候,当你把它那个对象展开,就会发现它里面有很多虚的,浅紫色的东西。
这些东西其实就证明,这是一个虚的,一个抽象的东西,它并不是真正存在的。
比如我直接去找 json 里面有没有一个 a,你根本就找不了:
其实你是被迫的需要执行 get a 这个函数,它只是一个虚的东西,并不是一个真实的方法,这就是它的由来。
所以到这为止,我们就大概的理解了 defineProperty 的作用。
其实也没什么,它就是给某个对象,比方说 json,我们给它添加了一个 'a',表面上看来是一个属性,但其实它背后对应的是一些函数,然后在里面我们可以进行各种各样的操作。
然后接下来,我们还有一个小事,就是我们平常对数据进行操作,不一定只是获取和设置,有没有可能我想把这个数据删了?
比如,现在我就要把这个 json.a 删除掉:
这时候它给我返回一个 false。
相信大家都能猜到这个 false 的意思,代表着没删掉。
比如,我们再次访问 json.a:
可以看到,这个 json 它依然是有 a 的。
注意,用 defineProperty 去设置的属性,不是直接用 delete 就能删掉的,我们还需要一个东西才行。
实际上来说,这时候我们就需要用到它里面的其他参数了,它里面还有其他的一些参数可以供我们来选择,并不是只有 get 和 set。
所以这时候,我们就需要一个东西,叫做 configurable,就是可配置的意思。
当我们没写的时候,configurable 默认会是一个 false:
可以看到,当我们写上 configurable: false 的时候,它还是删不了,和没加一样。
因为 configurable 默认就是 false,不可配置嘛。
那如果我们给它一个 true,意思就是说,我这个属性 a 是可配置的,可配置就意味着可以删:
可以看到,现在 delete 就是 true 了。
并且现在我在找 json.a,它就是 undefined 了。
因为刚才那个 get 和 set 就都消失了,它就是干这个用的。
那么我们稍微来总结一下:
你可以看到 defineProperty 就比我们上篇博客说的访问器,更为的复杂,当然功能也更加的强大。
当你去定义某一个属性的时候,你可以指定很多的东西,当然我们现在说的是最实用的三个东西:get,set,configurable。(其实它还有别的东西,不过意义和用处不大,我们一般就用这三个)
然后定义属性的时候,可以顺便的去指定一些属性的行为,比如是否可配置。(可配置包括 2 个,改和删,一般情况下,我们用的都是删除)