js中的物件有一些內部才用的特性,這些特性是為了實現javascript引擎用的,因此在javascript中不能直接訪問它們。
有兩種屬性:資料屬性 && 訪問器屬性
資料屬性
- [[ configurable ]]: 表示能否通過 delete 刪除屬性然後重新定義屬性,能否修改屬性的特性,或者能否把屬性修改為訪問器屬性。直接在物件上定義的屬性,它們這個特性的預設值為 true;
- [[ enumerable ]]: 表示能否通過 for-in 迴圈返回屬性。直接在物件上定義的屬性,它們這個特性的預設值為 true;
- [[ writable ]]: 表示能否修改屬性的值。直接在物件上定義的屬性,它們這個特性的預設值為 true;
- [[ value ]]: 包含這個屬性的資料值。讀取屬性值的時候,從這個位置讀;寫入屬性的時候,把新值儲存在這個位置。這個特性的預設值為 undefined ;
要修改屬性的特性,必須使用 ES5 的 Object.definePrototype()
方法。這個方法接受三個引數:
1、屬性所在的物件。
2、屬性的名字。
3、描述符物件。屬性必須是:configurable
、enumerable
、writable
、value
中的一個或多個。
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()
方法建立一個新的屬性時,如果不指定,configurable
、enumerable
、writable
特性的預設值都是 false,如果是修改已存在的屬性,就不會有這個限制。
訪問器屬性
訪問器屬性沒有資料值,有get
、 set
函式。讀取訪問器屬性時,會呼叫 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" 屬性值。
不一定非要同時指定 set
、get
函式。只指定 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、屬性名稱。
返回值是一個物件,如果是資料屬性,這個物件的屬性有:configurable
、enumerable
、writable
、value
。
如果是一個訪問器屬性,物件的屬性有:configurable
、enumerable
、get
、set
。
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()方法。