JavaScript中监听对象的操作方式
文章目录
- 前言
- 一、对象
- 1. 声明语法
- 2. 声明语法
- 3. 二者唯一区别
- 二、Object.defineProperty
- 三、属性描述符
- 1. 数据描述符
- 2. 存取描述符
- 3. 错误操作导致报错
- 总结
前言
Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。
一、对象
对象可以通过两种形式定义,声明形式和构造形式
1. 声明语法
var myObj = {
key: value
//...
}
2. 声明语法
var myObj = new Object()
myObj.key = value
3. 二者唯一区别
在声明形式中,可以添加多个 键 / 值对,但是在构造形式中必须逐个添加属性
构造形式:
二、Object.defineProperty
由上面的例子可以看出,无论是通过声明形式
或构造形式
创建对象,该对象都可以枚举(即通过 for...in
或 Object.keys
方法获取到该对象的属性值)且属性值可以后续更改
但是在某些特定的场景下,我们定义完对象之后,在后续操作不让更改其属性值或者无法枚举,这种应该怎么操作呢?
于是 Object.defineProperty() 来了
三、属性描述符
-
目前属性描述符有两种主要形式:数据描述符和存取描述符
-
数据描述符
是一个具有值的属性,该值可以是可写的,也可以是不可写的 -
存取描述符
是由 getter 函数和 setter 函数所描述的属性 -
一个描述符只能是这两者其中之一;不能同时是两者
1. 数据描述符
有了属性描述符,可以更加细腻的控制属性的不同操作,它们分别为:
- configurable //属性值是否可以改变
- writable //是否能写入
- enumerable //支持枚举
属性描述符通常和 Object.defineProperty 一起定义属性
2. 存取描述符
存取描述符由一对getter - setter 函数功能来描述的属性
name: {
get: function() { ... },
set: function(newVal) { ... },
enumerable: true,
configurable: true
}
var obj = {}
Object.defineProperty(obj, 'name', {
configurable: true,
enumerable: true,
get: function() {
console.log('get')
return this.value
},
set: function(newVal) {
console.log('set')
this.value = newVal
}
})
// 赋值会调用 set 方法
obj.name = '猪八戒'
// 取值会调用 get 方法
obj.name
3. 错误操作导致报错
TypeError: Invalid property descriptor. Cannot both specify accessors and a value or writable attribute
转载
这个错误是因为:Object.defineProperty(object, propertyName, descriptor) 定义新属性时,descriptor 中同时有 访问器(getter/setter) 与 value/writable 属性。
如果一个描述符同时拥有 value 或 writable 和 get 或 set 键,则会产生一个异常
测试代码
var obj = {}
// value和 get 只能同时用一个
Object.defineProperty(obj, 'name', {
value: '孙悟空',
get: function() {
console.log('get')
return this.value
}
})
// writable和set只能同时用一个
Object.defineProperty(obj, 'name', {
writable: true,
set: function(newValue) {
console.log('set')
}
})
-
Object.defineProperty 的设计初衷,并不是为了监听劫持一个对象中所有属性的
-
如果想要监听更多的操作,比如新增、删除属性,那么Object.definePropertys是没法办法做到的
Object.defineProperty 是Vue2中的响应式核心
优点:
- 兼容性好,支持 IE9,而 Proxy 的存在浏览器兼容性问题,而且无法用 polyfill 磨平
缺点:
- 只能劫持对象的属性,对每个对象的每个属性都要进行遍历
- 不能监听数组。是通过重写数据的那7个可以改变数据的方法来对数组进行监听的
- 不能对 es6 新产生的 Map,Set 这些数据结构做出监听
- 对于监听新增和删除操作,通过 Vue.set()和 Vue.delete来实现响应式的
总结
以上就是JavaScript中监听对象的描述符的讲解