ECMAScript5 Object新增的方法

2016年11月09日Web前端

系统的学习Object新增的方法,可以让我们能够更加灵活地使用Object,当然IE版本必须满足9或以上。

Object.create(prototype, descriptors)

以指定的原型创建对象,并且可以(可选)的设置对象的属性。

function Person(name, age) {
    this.name = name;
    this.age = age;
}
var people = Object.create(new Person('Li', 23));
Person.constructor;           // function Function() { \[native code\] }
new Person().constructor;     // function Person(name, age) {
                              //     this.name = name;
                              //     this.age = age;
                              // }
Person.constructor.prototype; // function () {}
Person.prototype == new Person().constructor.prototype; // true
Person.constructor.prototype == new Person().constructor.prototype; // false
Person.prototype == people.constructor.prototype; // true
Person.constructor.prototype == people.constructor.prototype; // false
people.age  // 23
people.name // 'Li'

其实,Object.create构造的对象和用构造函数构造的对象在结果上没有什么差异。用Object.create的好处是原型链干净,网上有有给出了以下没有Object.create的浏览器的解决同样解决方案。以下代码不但说明了Object.create的技术内幕,同时可以支持低版本的IE同样可以实现干净的原型。

if (typeof Object.create !== 'function') { 
    Object.create = function(o) { 
        function F() {} 
        F.prototype = o; 
        return new F(); 
    };
}

当然,为了得到一个原型链上没有任何属性或方法的对象,我们可以使用这种方法:

var obj = Object.create(null);
obj.toString()  //  Uncaught TypeError: obj.toString is not a function
obj.prototype  //  undefined

Object.defineProperty(object, propertyname, descriptor)

将属性添加到对象,或修改现有属性的特性。第一个参数是要操作的对象,第二参数是操作的字段,第三参数是取值。

var obj = {};
Object.defineProperty(obj, 'a', {
    value: 11
});
console.log(obj.a); // 11

看上去和直接给obj.a = 11差不多,但是这只是表面上而已。value只是descriptor中的一种值。descriptor的值有:

  • value 属性的值,默认undefined
  • writable 表示属性是否可修改,默认是false
  • configurable 表示能否通过delete删除属性而重新定义,能否修改属性的特性,能否把属性修改为访问器熟属性,默认是false
  • enumerable 表示是否可通过for-in或Object.keys()枚举,默认false
  • get 访问器属性(见下文)
  • set 访问器属性(见下文)

对于刚才的操作(第一次设置时),其实相当于这样:

Object.defineProperty(obj, 'a', {
    value: 11,
    configurable: false,
    writable: false,
    enumerable: false
});

configurable像是总开关,当被设置成false时,将无法再次调用该函数。如:

var obj = {};
Object.defineProperty(obj, 'a', {
    value: 11,
    configurable: false
});
Object.defineProperty(obj, 'a', {  // Uncaught TypeError: Cannot redefine property: a
    configurable: true
});

当writable被设置成false时,我们仍给变量复制时,并不会报错,但值不会被修改。

var obj = {};
Object.defineProperty(obj, 'a', {
    value: 11,
    writable: false
});
obj.a = 11111;       // 不会报错
console.log(obj.a);  // 11

enumerable就是枚举使用,不在举例。

get、set访问器属性

在 descriptor 中不能同时设置访问器 (get 和 set) 和 writable或 value,否则会错。

var obj = {};
Object.defineProperty(obj, 'a', {
    get: function() {
        console.log('get');
    },
    set: function(value) {
        console.log('set ' + value);
    },
    enumerable: true,
    configurable: true
});
obj.a = 11; // set 11
obj.a;      // get

Object.defineProperties(object, descriptors)

该方法和前一个方法的用法是一样的,不同的就是该方法可以一次添加多个属性。其他用法同前一个函数。

var obj = {};
Object.defineProperties(obj, {
    'a': {
        value: 11
    },
    'b': {
        get: function() {
            alert();
        },
        set: function() {
            alert();
        }
    }
});

Object.getOwnPropertyDescriptor(object, propertyname)

用于获取对象已经被定义的属性。

var obj = {};
Object.defineProperty(obj, 'a', {
    configurable: true,
    enumerable: true,
    writable: true,
    value: 12
});
var descriptor = Object.getOwnPropertyDescriptor(obj, 'a');
console.log(descriptor); // Object {value: 12, writable: true, enumerable: true, configurable: true}

Object.getOwnPropertyNames(object)

返回所有属性的名称,哪怕说是不能枚举的属性。

var obj = {};
Object.defineProperty(obj, 'a', {
    configurable: false,
    enumerable: false,
    writable: false,
    value: 12
});
var values = Object.getOwnPropertyNames(obj);
for (var i = 0; i < values.length; ++i) {
    console.log(Object.getOwnPropertyDescriptor(obj, values\[i\]));
    // Object {value: 12, writable: false, enumerable: false, configurable: false}
}

Object.preventExtensions(object)

可以阻止对象添加新的属性,但属性的值可以改,也可以删除。

var obj = {
    'a': 1,
    'b': 2
};
Object.preventExtensions(obj);
obj.c = 3;
console.log(obj); // Object {a: 1, b: 2}

Object.isExtensible(object)

对象是否可以添加属性。

var obj = {};
var obj1 = {};
var obj2 = {};
Object.preventExtensions(obj);
console.log(Object.isExtensible(obj));  // false
console.log(Object.isExtensible(obj1)); // true
console.log(Object.isExtensible(obj2)); // true

Object.seal(object)

对象不能添加和删除属性。

var obj = {
    'a': 1,
    'b': 2
};
Object.seal(obj);
delete obj.a;
obj.c = 3;
console.log(obj); // Object {a: 1, b: 2}

Object.isSealed(object)

对象是否不能添加和删除属性。

Object.freeze(object)

防止现有属性和属性值的修改,并防止新特性的添加。

var obj = {
    'a': 1,
    'b': 2
};
Object.freeze(obj);
delete obj.a;
obj.c = 3;
obj.b = 222;
console.log(obj); // Object {a: 1, b: 2}

Object.isFrozen(object)

对象是否freeze了。

Object.getPrototypeOf(object)

用于得到对象的原型。

var obj = {
    'a': 1,
    'b': 2
};
console.log(Object.getPrototypeOf(obj)); //Object {}
var obj = Object.create(null);
console.log(Object.getPrototypeOf(obj)); //  null

ObjectA.isPrototypeOf(ObjectB)

判断B是否是A派生的一个实例

var o = {
    'a': 1
};
var obj = Object.create(o);
console.log(o.isPrototypeOf(obj)); // true

Object.hasOwnProperty()

判断属性是否存在于对象的实例中,与in不同,不会检索原型上的属性。

var o = {
    'a': 1
};
var obj = Object.create(o);
obj.b = 2;
console.log(obj.hasOwnProperty('b')); // true
console.log(obj.hasOwnProperty('a')); // false

Object.keys()

遍历实例对象的属性,与in不同,不会遍历原型上的属性,返回一个数组,包含所有的属性名。

var o = {
    'a': 1
};
var obj = Object.create(o);
obj.b = 2;
obj.c = 3;
console.log(Object.keys(obj)); // \["b", "c"\]