物件導向--內部屬性型別

要吃早餐發表於2018-03-30

js中的物件有一些內部才用的特性,這些特性是為了實現javascript引擎用的,因此在javascript中不能直接訪問它們。

有兩種屬性:資料屬性 && 訪問器屬性

資料屬性

  • [[ configurable ]]: 表示能否通過 delete 刪除屬性然後重新定義屬性,能否修改屬性的特性,或者能否把屬性修改為訪問器屬性。直接在物件上定義的屬性,它們這個特性的預設值為 true;
  • [[ enumerable ]]: 表示能否通過 for-in 迴圈返回屬性。直接在物件上定義的屬性,它們這個特性的預設值為 true;
  • [[ writable ]]: 表示能否修改屬性的值。直接在物件上定義的屬性,它們這個特性的預設值為 true;
  • [[ value ]]: 包含這個屬性的資料值。讀取屬性值的時候,從這個位置讀;寫入屬性的時候,把新值儲存在這個位置。這個特性的預設值為 undefined ;

要修改屬性的特性,必須使用 ES5 的 Object.definePrototype() 方法。這個方法接受三個引數:

1、屬性所在的物件。

2、屬性的名字。

3、描述符物件。屬性必須是:configurableenumerablewritablevalue中的一個或多個。

var obj = {};
Object.defineProperty(obj, 'name', {
    writable: false,  // 不能修改值
    value: '張三'
})
console.log(obj.name); // 張三
obj.name = '李四';
console.log(obj.name); // 張三,  writable設為 false 後,值就沒法修改了。
var person = {
    name: '李四',
    age: 24
}
delete person.name;
console.log(person); // {age: 24}
Object.defineProperty(person, 'age', {
    configurable: false
})
delete person.age; 
console.log(person);// {age: 24} configurable特性設為 false 後,就沒法使用 delete 刪除了。
複製程式碼

把 configurable 設定為 false 後,就不能用 delete 刪除屬性,而且,也不能修改 除 writable 外的特性。

var obj = {};
Object.defineProperty(obj, "name", {
    configurable: false,
    value: '張三'
})

// 會丟擲錯誤
Object.defineProperty(obj, "name", {
    configurable: true,
    value: '張三'
})
複製程式碼

物件導向--內部屬性型別
也就是說,可以多次呼叫 Object.defineProperty()方法修改同一個屬性,但在把 configurable特性設定為 false 後就有限制了。

在呼叫Object.defineProperty()方法建立一個新的屬性時,如果不指定,configurableenumerablewritable 特性的預設值都是 false,如果是修改已存在的屬性,就不會有這個限制。

訪問器屬性

訪問器屬性沒有資料值,有getset函式。讀取訪問器屬性時,會呼叫 get函式,在寫入值時會呼叫set函式。

訪問器屬性有如下四個特性:

  • [[ configurable ]]: 表示能否通過 delete 刪除屬性,從而重新定義屬性。能否修改屬性的特性,或者能否把屬性修改為資料屬性。直接在物件上定義的屬性,它們這個特性的預設值為 true;
  • [[ enumerable ]]: 表示能否通過 for-in 迴圈返回屬性。直接在物件上定義的屬性,它們這個特性的預設值為 true;
  • [[ get ]]: 讀取屬性時,呼叫的函式。預設值為 undefined;
  • [[ set ]]: 寫入屬性時,呼叫的函式。預設值為 undefined;

訪問器屬性不能直接定義,必須通過Object.defintProperty()來定義。

"use strict"
let person = {
    name: '張三',
    age: 25
}
Object.defineProperty(person, 'oldAge', {
    get: function () {
        return this.age + 1;
    },
    set: function (newValue) {
        if (newValue > this.age) {
            this.age = newValue - 1;
            this.name = '李四'
        } else {
            this.age = newValue + 1;
            this.name = "王五"
        }
    }
})

person.oldAge = 28;
console.log(person); // {name: '李四', age: 27};
複製程式碼

上面定義了一個 person 物件。預設有兩個屬性, "name"、"age"。新增了一個訪問器屬性 "oldAge"。它包含了兩個函式。 get 函式用來返回值。set函式,當為 "oldAge"寫入值的時候,會呼叫。把 oldAge 設定為 27 後,呼叫 set 函式,改變了 person 物件的 "name" 和 "age" 屬性值。

不一定非要同時指定 setget函式。只指定 get函式,意味著屬性不能寫,嚴格模式會報錯。只指定了set函式,屬性就不能讀取,嚴格模式同樣會報錯。


定義多個屬性

ES5 定義了一個 Object.defineProperties() 方法,可以通過描述符一次定義多個屬性。這個方法,接受兩個物件引數:第一個是要新增和修改其屬性的物件,第二個就是要設定的屬性的物件。

let car = {};
Object.defineProperties(car, {
    createYear: {
        writable: false,
        value: 2010
    },
    color: {
        writable: true,
        value: 'block'
    },
    severalYear: {
        get: function () {
            return parseInt(new Date().getFullYear()) - this.createYear
        },
        set: function (newValue) {
            if (newValue > 2010) {
                this.color = 'red';
            }
        } 
    }
})
console.log(car.createYear); // 2010
console.log(car.color);  // 'block'
console.log(car.severalYear); // 8
car.severalYear = 2015;
console.log(car.createYear); // 2010
console.log(car.color);  // 'red'
console.log(car.severalYear);  // 8
複製程式碼

需要注意的是:雖然我們設定 car.severalYear = 2015. 但是car.severalYear的值並沒有改變。因為為訪問器屬性寫入值的時候,只是會去執行 set 函式,而真實的值只能是通過get函式返回。


讀取屬性的特性

使用 ES5 的 Object.getOwnPropertyDescriptor()方法,可以取得給定屬性的描述符。這個方法接受兩個引數:

1、屬性所在的物件。

2、屬性名稱。

返回值是一個物件,如果是資料屬性,這個物件的屬性有:configurableenumerablewritablevalue。 如果是一個訪問器屬性,物件的屬性有:configurableenumerablegetset

let car = {};
Object.defineProperties(car, {
    createYear: {
        writable: false,
        value: 2010
    },
    color: {
        writable: true,
        value: 'block'
    },
    severalYear: {
        get: function () {
            return parseInt(new Date().getFullYear()) - this.createYear
        },
        set: function (newValue) {
            if (newValue > 2010) {
                this.color = 'red';
            }
        } 
    }
})

let descriptpor = Object.getOwnPropertyDescriptor(car, "createYear");
console.log(descriptpor);
// { value: 2010,
//   writable: false,
//   enumerable: false,
//   configurable: false }

let fangdescriptpor = Object.getOwnPropertyDescriptor(car, "severalYear");
console.log(fangdescriptpor); // 看下圖
複製程式碼

物件導向--內部屬性型別

在 JavaScript 中可以針對任何物件-----包括 DOM 和 BOM 物件使用 Object.getOwnPropertyDescriptor()方法。

相關文章