js對象、對象拷貝、對象凍結


一。對象的屬性描述

JavaScript “屬性描述對象”(attributes object

{

  value: 屬性的屬性值

  writable:是否可寫

  enumerable:是否可遍歷 比如for...in循環、Object.keys())跳過該屬性

  configurable: 可配置性控制了屬性描述對象的可寫性

  get: undefined,取值函數(getter,默認為undefined

  set: undefined,存值函數(setter,默認為undefined

}

 

二。獲取屬性

1.  Object.getOwnPropertyDescriptor():獲取指定屬性的描述值(只能用於對象自身的屬性,不能用於繼承的屬性

  參數:第一個參數是目標對象,第二個參數是一個字符串(對應目標對象的某個屬性名),效果如下:

 

 

2.  Object.getOwnPropertyNames():方法返回一個數組,成員是參數對象自身的全部屬性的屬性名,不管該屬性是否可遍歷。【Object.keys只返回對象自身的可遍歷屬性的全部屬性名】

 

 

  

3.  Object.defineProperty():允許通過屬性描述對象,定義修改一個屬性,然后返回修改后的對象。

  定義和修改🌰:如下定義一個對象obj,有一個p屬性,定義p屬性的writable為false,則可以看到修改p值后,並沒有生效。【其次,當定義一個存在的屬性時,即是修改了】

     

 

如果一次性定義或修改多個屬性,可以使用Object.defineProperties()方法:如下

var obj = Object.defineProperties({}, {
  p1: { value: 123, enumerable: true },
  p2: { value: 'abc', enumerable: true },
  p3: { get: function () { return this.p1 + this.p2 },
    enumerable:true,
    configurable:true
  }
});

obj.p1 // 123
obj.p2 // "abc"
obj.p3 // "123abc"

 

4.  Object.prototype.propertyIsEnumerable():返回一個布爾值,用來判斷某個屬性是否可遍歷。注意,這個方法只能用於判斷對象自身的屬性,對於繼承的屬性一律返回false

  

 

 

5.  對象的拷貝:hasOwnProperty那一行用來過濾掉繼承的屬性,否則可能會報錯,因為Object.getOwnPropertyDescriptor讀不到繼承屬性的屬性描述對象。

 

var extend = function (to, from) {
  for (var property in from) {
    if (!from.hasOwnProperty(property)) continue;
    Object.defineProperty(
      to,
      property,
      Object.getOwnPropertyDescriptor(from, property)
    );
  }

  return to;
}

extend({}, { get a(){ return 1 } })
// { get a(){ return 1 } })

 

 

 

6.  對象凍結(控制對象狀態):凍結對象的讀寫狀態,防止對象被改變。

方案一:最強的Object.freeze。【無法添加新屬性、無法刪除舊屬性、也無法改變屬性的值,使得這個對象實際上變成了常量

  對應檢查方法:Object.isFrozen

var obj = {
  p: 'hello'
};

Object.freeze(obj);

obj.p = 'world';
obj.p // "hello"

obj.t = 'hello';
obj.t // undefined

delete obj.p // false
obj.p // "hello"

 

方案二:其次的Object.seal。【無法添加新屬性,也無法刪除舊屬性(可修改)】【實質是把屬性描述對象的configurable屬性設為false

  對應檢查方法:Object.isSealed

var obj = {
  p: 'a'
};

// seal方法之前
Object.getOwnPropertyDescriptor(obj, 'p')
// Object {
//   value: "a",
//   writable: true,
//   enumerable: true,
//   configurable: true
// }

Object.seal(obj);

// seal方法之后
Object.getOwnPropertyDescriptor(obj, 'p')
// Object {
//   value: "a",
//   writable: true,
//   enumerable: true,
//   configurable: false
// }

Object.defineProperty(o, 'p', {
  enumerable: false
})
// TypeError: Cannot redefine property: p

 

方案三:最弱的Object.preventExtensions。【無法再添加新的屬性

 

 

  對應檢查方法:Object.preventExtensions

var obj = new Object();
Object.preventExtensions(obj);

Object.defineProperty(obj, 'p', {
  value: 'hello'
});
// TypeError: Cannot define property:p, object is not extensible.

obj.p = 1;
obj.p // undefined

 

上面的三個方法鎖定對象的可寫性有一個漏洞:

  1.  可以通過改變原型對象,來為對象增加屬性。【除非obj的原型也凍結住

  2.  如果屬性值是對象,上面這些方法只能凍結屬性指向的對象,而不能凍結對象本身的內容。如下:

  

var obj = {
  foo: 1,
  bar: ['a', 'b']
};
Object.freeze(obj);
obj.bar.push('c');
obj.bar // ["a", "b", "c"]
上面代碼中,obj.bar屬性指向一個數組,obj對象被凍結以后,這個指向無法改變,即無法指向其他值,但是所指向的數組是可以改變的。

 

 

 

 

 

 

 

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM