彻底弄懂 defineProperty
彻底弄懂 defineProperty
Vue.js 的流行将其数据双向绑定的核心带到了大家面前,那就是 Object.defineProperty()
,在详细讲解这个方法之前,我们先用一段最简单的代码实现一个最简单的数据响应。
<div id="main"></div>
let info = {}
Object.defineProperty(info, 'name', {
get: function () {
return document.getElementById('main').innerHTML
},
set: function (value) {
document.getElementById('main').innerHTML = value
}
})
info.name = "hello"
这里当我们修改 info.name
的值的时候就会动态反馈到 HTML 元素上。这里的核心就是 set
定义了在给 info 对象设置值的时候会自动去执行 set
中的代码,从而达到了数据绑定的效果。起到了一个触发器的效果。
当然这仅仅是一个简单的示例,实际上 Vue.js 并不是单纯地通过数据和 DOM 节点的绑定来绑定数据,在此之间还有 Wacher
和 Directive
,这里不细说,接下来主要看看 Object.defineProperty()
到底是什么。
作用
给指定对象加上新的属性或者修改原有属性的值
返回值
被操作的对象
语法
Object.defineProperty(obj, prop, descriptor)
参数
obj
:要操作的对象prop
:要修改或新增的属性名称descriptor
:属性描述符
接下来着重讲讲属性描述符
属性描述符
属性描述符(descriptor
) 顾名思义就是如何描述(设置)指定属性,分为两种:数据描述符 和 存取描述符。
数据描述符
可选键值有
value
要设置的具体值。可以是任何有效的 JavaScript 值(数值,对象,函数等)。默认为
undefined
。
writable
规定该属性是否可被赋值运算符(=)改变。默认为
false
。
var obj = {}
Object.defineProperty(obj, 'name', {
value: 'lucy',
writable: false
})
那么 obj
为 {name: "lucy"}
,然后我们再修改
obj.name = 'tom'
此时 obj
仍然是 {name: "lucy"}
,因为我们定义了 name 属性的 writable
为 false
是不能被赋值运算符修改的(注意这里并不会报错)。当然不设置 writable
的值也是可以的,因为其默认值就是 false
。
存取描述符
可选键值有
get
一个给属性提供
getter
的方法。当访问该属性时,该方法会被执行,默认为undefined
set
一个给属性提供
setter
的方法,当属性值修改时,触发执行该方法,默认为undefined
这俩其实就是在给属性赋值或者取值的时候的一个 触发器。
var obj = {}
Object.defineProperty(obj, 'name', {
set: function (value) {
},
get: function () {
}
})
公共键值
除了上面两种描述符各自独有的键值,他们还有公共的键值可用
configurable
表示该属性是否可以被删除,以及除
writable
特性外的其他特性是否可以被修改。默认为false
enumerable
定义了对象的属性是否可以在
for...in
循环和Object.keys()
中被枚举。默认为false
var obj = {
age: 12
}
Object.defineProperty(obj, 'name', {
value: 'tom',
enumerable: false
})
这里 obj 变成了 {age: 12, name: "tom"}
但是我们执行
Object.keys(obj)
得到的却是 ["age"]
,可见 enumerable
确实影响到了 Object.keys()
的取值。当然直接写成下面这样也是可以的
Object.defineProperty(obj, 'name', {
value: 'tom'
})
因为 enumerable
的默认值就是 false
注意,如果同时设置了数据描述符和存取描述符,是会出现异常的,比如我这样写
var obj = {}
Object.defineProperty(obj, 'name', {
set: function (value) {
},
value: 'tom'
})
则会报错
Invalid property descriptor. Cannot both specify accessors and a value or writable attribute
数据描述符默认值
需要注意的是,以两种不同的方式给属性赋值时,数据描述符中的属性默认值是不同的。
1、点运算
var obj = {}
obj.name = 'tom'
等价于
Object.defineProperty(obj, 'name', {
value : 'tom',
writable : true,
configurable : true,
enumerable : true
})
2、Object.defineProperty()
Object.defineProperty(obj, 'name', {
value : 'tom',
})
等价于
Object.defineProperty(obj, 'name', {
value : 'tom',
writable : false,
configurable : false,
enumerable : false
})
还没有评论,来说两句吧...