JavaScript ES5中的Object.defineProperty()方法
2017年2月9日

JS中的对象类型:var obj = {a:1},可以通过变量.属性名的形式进行取值、赋值,这种方式虽然便捷,但其创建的属性值可以被任意修改,并可以通过for...in枚举。__Object.defineProperty()__可以定义、修改对象属性的值及其特性。如今流行的数据双向绑定的JS库中广泛使用了该方法。

语法

首先我们来看一下__Object.defineProperty()__的语法,该函数接收三个参数:

Object.defineProperty(obj, prop, descriptor)

参数

参数名 类型 描述
obj Object 要定义或修改的属性所处的对象
prop String 要定义或修改的属性名
descriptor Object 针对该属性的描述

返回值

传入的对象

属性描述

第三个参数是一个对象,是针对要定义或修改的属性的详细描述,该对象可以由以下属性组成:

属性名 作用 默认值
configurable 该属性是否可以被删除以及其特性是否能够再被修改 false
enumerable 该属性是否可以通过for...in枚举出并且列在Object.keys(obj)的结果中 false
value 该属性的值 undefined
writable 该属性是否可以通过“=”来赋值 false
get 存取器getter,传入一个函数,其返回值即是该属性的值 undefined
set 存取器setter,传入一个函数,只接受一个参数,这个参数为该属性的赋值 undefined

Configurable & Enumerable

  • 如果属性的__configurable__特性一旦被设为false后,将无法再通过__Object.defineProperty()__改变该属性的特性,并且该属性也无法被删除。
  • 如果属性的__enumerable__特性为true,那么可以使用for...in来枚举出该属性,并且__Object.keys()__方法也列出该属性。
var obj = {};

Object.defineProperty(obj, 'name', {
    value: 'John',
    configurable: true,
    enumerable: true
});
Object.keys(obj); // Array [ "name" ]

Object.defineProperty(obj, 'name', {
    enumerable: false,
    configurable: false
});
Object.keys(obj); // Array [  ]

Object.defineProperty(obj, 'name', {
    enumerable: true
}); // TypeError: can't redefine non-configurable property "name"
delete obj.name; // false
obj.name; // "John"

Value & Writable

属性的__writable__特性为false时,该属性的值无法进行赋值运算(即:无法使用“=”来赋值),但依旧可以通过__Object.defineProperty()__来更改属性值。

var obj = {};
Object.defineProperty(obj, 'name', {
    value: 'John',
    writable: false,
    configurable: true
});
console.log(obj.name); // "John"

obj.name = 'Marry';
console.log(obj.name); // "John"

Object.defineProperty(obj, 'name', {
    value: 'Marry'
});
console.log(obj.name); // "Marry"
var obj = {};
obj.name = 'John';

等价于:

var obj = {};
Object.defineProperty(obj, 'name', {
    value: 'John',
    writable: true,
    configurable: true,
    enumerable: true
});

Getter && Setter

  1. get方法会在获取该属性值的时候执行,属性值即为该方法的返回值
  2. set方法会在对该属性进行赋值运算(即:使用“=”来赋值)时执行
  3. set和get方法不能与value并存,也就是说定义了存取器之后,无法再通过__Object.defineProperty()__进行赋值。
var Person = function(name) {
    var nameValue;
    Object.defineProperty(this, 'name', {
        set: function(name) {
            nameValue = name.substr(0, 1).toUpperCase().concat(name.substring(1));
        },
        get: function() {
            return nameValue;
        }
    });
    this.name = name;
};
var john = new Person('john');
console.log(john.name); // "John"

浏览器支持

  • Chrome 5 +
  • FireFox 4 +
  • IE 9+
  • Opera 11.60 +
  • Safari 5.1 +

参考

分类

JavaScript ES5