Dean Front-end Dev Engineer

JS 中的对象

2018-02-17

对象的比较

对象的比较都是引用的比较,因此,在比较对象的属性和值是否全等时,不能直接比较。通常要用 JSON.stirngify() 转为字符串后,再比较字符串。

var arr1 = [1,2],arr2 = [1,2];
console.log(arr1 === arr2);//false
console.log(JSON.stirngify(arr1) === JSON.stirngify(arr2));//true

var a = {}, b = {}, c = {};//a、b、c每个都引用一个不同的空对象
a = b = c = {};c = {}; b = c; a = b; //a、b、c都引用同一个空对象

数据属性

数据属性有四个描述其行为的特性:

  • [[configurable]]:表示是否能够通过delete删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性。当直接在对象上定义属性时,这个值默认为true
  • [[Enumerable]]:表示能否通过for-in循环返回属性。当直接在对象上定义属性时,这个值默认为true
  • [[Writable]]:表示能否修改属性的数据值Value。当直接在对象上定义属性时,这个值默认为true
  • [[Value]]:包含这个属性的数据值。这个特性默认值为undefined。

要修改属性的默认特性的值,必须使用 Object.defineProperty() 或 Object.defineProperties() 方法修改(一个或多个特性)。这个方法接收三个参数:属性所在的对象、属性的名字和一个描述符对象。 而由Object.defineProperty() 或 Object.defineProperties() 创建的特性,默认值都为 false。

var person = {
    name:'wang',
    age:18
};
Object.defineProperty(person,'name',{
    writable:false;
});
person.name = 'li';
alert(person.name);//wang

访问器属性

访问器属性不包含数据值,它们包含一对 getter 和 setter 函数(不过,这两个函数也不是必须的)。 访问器属性有四个特性:

  • [[configurable]]:表示是否能够通过 delete 删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为数据属性。当直接在对象上定义属性时,这个值默认为 true。
  • [[Enumerable]]:表示能否通过 for-in 循环返回属性。当直接在对象上定义属性时,这个值默认为 true。
  • [[Get]]:在读取属性时调用函数。默认值为 undefined。
  • [[Set]]:在写入属性时调用的函数。默认值为 undefined。

注:访问器中没有 Writable 和 Value 这两个特性,因此不要设置这两个的值,否则出错。

var book = {
    _year : 2004,
    edition : 1
};
Object.defineProperty(book,"year",{ 
    get : function () {
        alert(this._year);
    },
    set : function (newValue) {
        if (newValue > 2004) {
            this._year = newValue;
            this.edition += newValue - 2004;
        }
    }
});
book.year;      // 弹出窗口,显示 2004
book.year = 2005;
console.log(book.edition);   // 2

专门读取数据属性和访问器属性的特性的值的方法: Object.getOwnPropertyDescriptor(),这个方法接收两个参数,属性所在的对象和属性名称。

var girl = {name: "zyj"};
console.log(Object.getOwnPropertyDescriptor(girl,"name"));
// Object {value: "zyj", writable: true, enumerable: true, configurable: true}
Object.defineProperties(girl,{
  name:{
    writable: false
  },
  age:{
    writable: true,
    value: 22
  }
});
console.log(Object.getOwnPropertyDescriptor(girl,"name"));
// Object {value: "zyj", writable: false, enumerable: true, configurable: true}
console.log(Object.getOwnPropertyDescriptor(girl,"age"));
// Object {value: 22, writable: true, enumerable: false, configurable: false}
var descriptor = Object.getOwnPropertyDescriptor(girl,"age");
console.log(descriptor.value);         // 22
console.log(descriptor.configurable);  // false
console.log(descriptor.writable);      // true
console.log(descriptor.get);           // undefined
console.log(descriptor.set);           // undefined

对象的扩展、密封及冻结三大特性

扩展特性

  • Object.isExtensible(obj) :判断一个对象是否可扩展(即是否可添加新属性)
  • Object.preventExtensions(obj) :让一个对象变得不可扩展。(仍可为该对象的原型添加新属性)

密封特性

密封对象是指那些不能添加新的属性,不能删除已有属性,以及不能修改已有属性的可枚举性、可配置性、可写性,但可能可以修改已有属性的值的对象。

  • Object.isSealed(obj) :判断一个对象是否是密封对象。
  • Object.seal(obj) :将一个对象密封。

冻结特性

冻结对象是指那些不能添加新的属性,不能修改已有属性的值,不能删除已有属性,以及不能修改已有属性的可枚举性、可配置性、可写性的对象。也就是说,这个对象永远是不可变的。

  • Object.isFrozen(obj) :判断是否是冻结对象
  • Object.freeze(obj) :把一个对象冻结

如果一个冻结对象的属性也是一个对象,那么这个对象的引用地址是不能变的,但属性是可变的。所以如果要彻底地冻结一个对象及其所有属性(一般称为深度冻结),则要递归遍历对象,把每一个对象属性也冻结。

Object.deepFreeze = function(obj) {
    var propNames = Object.getOwnPropertyNames(obj);
    propNames.forEach(function(name) {
        var prop = obj[name];
        if (typeof prop === 'object' && prop !== null) {
                Object.deepFreeze(prop); 
            }
        });
        return Object.freeze(obj);
}

Similar Posts

Comments