之前有了解到 Object.defineProperty 方法,能够在对象获取值或者设置值的时候进行一些操作,且 Vue.js 的双向绑定,也是通过这个方法实现的,所以现在觉得有必要深入的了解一番。
首先,先看看 Object.defineProperty 的基础用法,这个方法接收三个参数:
- 属性所在对象
- 属性的名字
- 描述符对象(descriptor)
其中,描述符(descriptor)对象的属性必须是:
- configurable: 表示能否通过
delete删除属性从而重新定义,能否修改属性的特性,或者能否把属性修改为访问器属性,默认值为false。 - enumerable: 表示能否通过
for-in循环返回属性,默认值为false。 - writable: 表示能够修改属性的值,默认值同为
false。 - value: 这个属性的数据值,就是我们常说的
value值,当我们读取属性值的时候,就是从这个位置读,当我们给属性赋值时,也是从这个位置写入,不同于上面的属性,这个属性的默认值是undefined。 - get: 在读取属性时调用的函数,默认值为
undefine。 - set:在写入属性时调用的函数,默认值为
undefine。
举个例子
var language = {}
Object.defineProperty(language, 'name', {
writable: false,
value: 'JavaScript'
})
console.log(language.name); // JavaScript
language.name = 'PHP';
cosnole.log(language.name); // JavaScript
以上代码中创建了一个 language ,并定义了属性为 name ,值为 JavaScript 的只读对象。这个属性的值是不可修改的,如果对这个属性进行重新赋值,在非严格模式下,赋值操作会被忽略;在严格模式下,赋值操作会导致程序抛出错误。
类似的操作也不适用 configurable 属性,例如
var language = {}
Object.defineProperty(language, 'name', {
configurable: false,
value: 'JavaScript'
})
console.log(language.name); // JavaScript
delete language.name;
cosnole.log(language.name); // JavaScript
以上代码中创建了一个 language ,并定义了属性为 name ,值为 JavaScript 的不可配置对象。这个属性是不可配置的,如果对这个属性进行删除处理,在非严格模式下,删除操作会被忽略;在严格模式下,删除操作会导致程序抛出错误。
不同于 writable ,一旦设置属性的 configurable 的值为 false , 就不能再更改为 true 了,如果尝试这样操作也会导致程序报错。
在调用 Object.defineProperty 方法时,如果不指定, configurable 、 enumerable 、 writable 特性的默认值都是 false 。
这里面要重点说一下 get 和 set 属性,看下面的例子
var language = {
_name: 'JavaScript',
author: 'Brendan Eich',
birth: 1995
}
Object.defineProperty(language, "name", {
get: function () {
return this._name;
},
set: function ( newValue ) {
if ( newValue !== this._name) {
this._name = 'this is not ' + this._name;
this.author = null;
this.birth = 0000;
}
}
})
console.log(language.name); // JavaScript
language.name = 'PHP';
console.log(language.name); // this is not JavaScript
从以上代码可以看出,通过 Object.defineProperty 给对象 language 创建了新属性 name ,而 name 设置了 get 和 set 函数。 get 函数返回 _name 值 JavaScript, set 函数通过判断传入的新值 newValue 是否等于 _name 值,如果不等于则会给 _name、 author 、 birth 重新赋值。
由于为对象定义多个属性的可能性很大, ECMAScript5 又定义了一个 Object.defineProperties 方法,利用这个方法可以通过描述符一次定义多个属性,以下为使用例子
var language = {}
Object.defineProperties(language, {
_name: {
writable: true,
value: 'JavaScript'
},
year: {
writable: true,
value: 1995
},
author: {
writable: true,
value: 'Brendan Eich'
},
name: {
get: function () {
return this._name;
},
set: function ( newValue ) {
if ( newValue !== this._name) {
this._name = 'this is not ' + this._name;
this.author = null;
this.birth = 0000;
}
}
}
})
这里需要说明的是,在定义属性时,如果这个值是需要改变的,需要加上 writable: true 才行,要不属性的的默认 writable 是为 false。