在 JavaScript 中,每個(gè)對(duì)象都是基于另一個(gè)對(duì)象創(chuàng)建的,也叫做對(duì)象的原型。所有對(duì)象都是通過其原型對(duì)象創(chuàng)建出來的。
不同的對(duì)象都有各自的屬性,ECMAScript 中有兩種類型的屬性:數(shù)據(jù)屬性和訪問器屬性。
數(shù)據(jù)屬性,就是最常見的有實(shí)實(shí)在在的值的屬性,訪問器屬性則是那些通過 getter 或 setter 函數(shù)進(jìn)行訪問和賦值的屬性。對(duì)于這兩種屬性,都有描述各自行為的特性。首先來看數(shù)據(jù)屬性。
數(shù)據(jù)屬性
數(shù)據(jù)屬性有以下幾個(gè)描述其行為的特性:
-
[[Configurable]]:此描述符表示是否能夠刪除該屬性,默認(rèn)為true -
[[Enumerable]]:此描述符表示該屬性是否可以通過for-in循環(huán)枚舉,默認(rèn)為true -
[[Writable]]:此描述符表示該屬性是否可寫,默認(rèn)為true -
[[Value]]:此描述符專門用來保存該屬性的值,讀取屬性時(shí),從這個(gè)位置讀取,寫入屬性時(shí)(如果該屬性可寫的情況下),就寫入在這個(gè)位置。該描述符的默認(rèn)值為undefined。
訪問器屬性
訪問器屬性不包含具體的屬性值,其包含了一對(duì) getter 和 setter 函數(shù)(非必須),在讀取屬性值時(shí),將調(diào)用 getter 函數(shù),將此函數(shù)的返回值作為讀取的值。在設(shè)置屬性時(shí),將調(diào)用 setter 函數(shù),在該函數(shù)中完成對(duì)屬性值的設(shè)置。
訪問器屬性有以下幾個(gè)描述其行為的特性:
-
[[Configurable]]:同上 -
[[Enumerable]]:同上 -
[[Get]]:讀取屬性時(shí)調(diào)用的函數(shù),默認(rèn)值為undefined -
[[Set]]:設(shè)置屬性時(shí)調(diào)用的函數(shù),默認(rèn)值為undefined
訪問器屬性不能直接定義,必須通過 Object.defineProperty() 來進(jìn)行定義。
Object.defineProperty() 方法
該方法用來對(duì)屬性進(jìn)行配置,包括數(shù)據(jù)屬性和訪問器屬性。該函數(shù)接受三個(gè)參數(shù):
- 屬性所在的對(duì)象
- 屬性名
- 屬性描述符對(duì)象
調(diào)用該方法返回被定義后的對(duì)象。
1.定義數(shù)據(jù)屬性
let ball = {name:"basketball",brand:"NIKE"};
Object.defineProperty(ball,"name",{
writable:false
}); //{name:"basketball",brand:"NIKE"}
ball.name = "pingpang";
ball.name //"basketball";
2.定義訪問器屬性
let ball = {}
Object.defineProperty(ball,"name",{
get:function(){
return this._name
},
set:function(name){
this._name = name
}
})
ball.name //undefined
ball.name = "籃球"
ball.name //"籃球"
ball._name //"籃球"
ball._name = "足球"
ball.name //"籃球"
在 getter 函數(shù)中,我們?cè)L問 name 屬性時(shí)返回當(dāng)前對(duì)象的 _name 屬性,在 setter 函數(shù)中,我們?cè)O(shè)置 name 的值時(shí)會(huì)設(shè)置設(shè)置該對(duì)象的 _name 屬性,也就是 name 屬性的值始終依賴于 _name 屬性的值,而當(dāng)我們修改 _name 屬性的值后,獲取到的 name 屬性的值也相應(yīng)變化了。
關(guān)于 [[Configurable]] 描述符
一旦將 [[Configurable]] 設(shè)置為 false 后,該屬性就變成了“不可配置”狀態(tài),此時(shí),除了對(duì) [[Writable]] 描述符進(jìn)行配置外,進(jìn)行其他的配置都會(huì)報(bào)錯(cuò)。
let ball = {}
Object.defineProperty(ball,"name",{
configurable:false,
value:"籃球"
})
// 再次配置
Object.defineProperty(ball,"name",{
configurable:true,
})
此時(shí)會(huì)產(chǎn)生錯(cuò)誤:
VM3119:1 Uncaught TypeError: Cannot redefine property: name
但是我們?nèi)匀豢梢詫?duì) [[Writable]] 描述符進(jìn)行配置:
Object.defineProperty(ball,"name",{
writable:false,
})
ball.name = "足球"
ball.name //"籃球"
定義多個(gè)屬性
ES5 還提供了定義多個(gè)屬性的方法:Object.defineProperties(),該方法接受兩個(gè)參數(shù),第一個(gè)參數(shù)是配置屬性的對(duì)象,第二個(gè)參數(shù)是一個(gè)針對(duì)待配置屬性的描述字典:
let ball = {}
Object.defineProperties(ball,{
name:{
writable:false
},
brand:{
configurable:false
}
})
獲取屬性特性
通過 Object.getOwnPropertyDescriptor() 方法,可以獲取對(duì)象的屬性的描述符。該方法接受兩個(gè)參數(shù):屬性所在的對(duì)象和屬性名。
let ball = {}
Object.defineProperties(ball,{
name:{
writable:false
},
brand:{
configurable:false
}
})
Object.getOwnPropertyDescriptor(ball,"name") //{value: undefined, writable: false, enumerable: false, configurable: false}
另外,還有一個(gè) Object.getOwnPropertyDescriptors()方法,可以獲取對(duì)象上所有的屬性特性,該方法只接受一個(gè)對(duì)象作為參數(shù),返回該對(duì)象所有的屬性描述符:
Object.getOwnPropertyDescriptors(ball)
返回值:
{
brand: {value: undefined, writable: false, enumerable: false, configurable: false},
name: {value: undefined, writable: false, enumerable: false, configurable: false}
}
完。