屬性類型
說(shuō)到屬性類型拆挥,指的是一個(gè)對(duì)象所擁有的所有屬性的特征薄霜。包括兩類:數(shù)據(jù)屬性和訪問(wèn)器屬性。
屬性類型的存在就是為了描述對(duì)象屬性的各種特性纸兔,當(dāng)初是為了實(shí)現(xiàn)js引擎用的惰瓜,因此在js中不能直接訪問(wèn),也可以理解為它是一個(gè)隱式的食拜,例如:[[prototype]]
數(shù)據(jù)屬性
數(shù)據(jù)屬性包含有一個(gè)數(shù)據(jù)值的位置鸵熟。在這個(gè)位置可以進(jìn)行數(shù)據(jù)的讀寫副编。數(shù)據(jù)屬性有4個(gè)描述其行為的特性负甸。
[[Configurable]]
:表示能否通過(guò)delete
刪除屬性從而重新定義屬性,也包括能否修改屬性的特性痹届,或者能否把屬性修改為訪問(wèn)器屬性呻待。默認(rèn)值為true
[[Enurmerable]]
:表示能否通過(guò)for-in
循環(huán)返回屬性,說(shuō)白了是否能遍歷队腐,或者可枚舉蚕捉。默認(rèn)值為true
[[Writable]]
:表示能否修改屬性的值,例如通過(guò)Object.defineProperty()
方法修改屬性的值柴淘。默認(rèn)值為true
[[Value]]
:包含這個(gè)屬性的數(shù)據(jù)值迫淹。讀取屬性值的時(shí)候,從這個(gè)位置讀为严。寫入屬性值的時(shí)候敛熬,把新的值保存在這個(gè)位置。默認(rèn)為undefined
例如:
let person = {
name: 'zhd',
age: 18,
sex: 'boy'
}
上面我定義了一個(gè)名為person的變量第股,并且添加了三個(gè)對(duì)應(yīng)的屬性应民,并指定對(duì)應(yīng)的值。也就是說(shuō)三個(gè)屬性對(duì)應(yīng)的個(gè)子的[[Value]]
這個(gè)特性就被賦予zhd
,18
,boy
這三個(gè)值夕吻,以后對(duì)每個(gè)值得修改都會(huì)體現(xiàn)在這個(gè)位置上诲锹。
但是,如果要修改屬性默認(rèn)的特性涉馅,必須使用Object.defineProperty()
方法归园。
Object.defineProperty()
:此方法接受三個(gè)參數(shù),第一個(gè)就是要修改的屬性所在的對(duì)象稚矿,第二個(gè)是要修改屬性名庸诱,第三個(gè)是描述符對(duì)象悬钳。這里需要注意一點(diǎn):描述符對(duì)象的屬性必須是configurable
,enumerable
,writable
,value
這四個(gè)。設(shè)置其中一個(gè)或多個(gè)值偶翅,可以修改對(duì)應(yīng)的特性值默勾。
例如:
var person = {}
Object.defineProperty(person, 'name', {
writable: false,
value: 'zhd'
})
console.log(person.name) // zhd
person.name = 'zy'
console.log(person.name) // zhd
如上面例子所示,修改了writable
特性值為false
,也就是不可寫或者說(shuō)不可更改聚谁,意思是一旦我設(shè)定了value
特性母剥,并且將其writable
設(shè)置為false
,后續(xù)的所有更改name
屬性值得行為都將不起作用形导。
這個(gè)規(guī)則同樣適用configurable
环疼,例如:
var person = {}
Object.defineProperty(person, 'name', {
configurable: false,
value: 'zhd'
})
console.log(person.name) // zhd
person.name = 'zy'
console.log(person.name) // zhd
將configurable
設(shè)置為false
,說(shuō)明不能用delete
刪除屬性朵耕。一旦把屬性定義為不可配置的炫隶,就不能把它變回可配置的。此時(shí)阎曹,如果再次調(diào)用Object.defineProperty()
方法修改除writable
外的所有屬性伪阶,都會(huì)導(dǎo)致錯(cuò)誤。
如下圖所示:
而對(duì)于
enumerable
处嫌,和writable
這兩個(gè)特性來(lái)說(shuō)栅贴,就好理解了,直接看定義就好了熏迹。
訪問(wèn)器屬性
訪問(wèn)器屬性不包含數(shù)據(jù)值檐薯;它們包含一對(duì)getter
和setter
函數(shù)。在讀取訪問(wèn)器屬性是注暗,會(huì)直接調(diào)用getter
函數(shù)坛缕,也就是說(shuō)getter
函數(shù)就相當(dāng)于訪問(wèn)的屬性值,這個(gè)函數(shù)負(fù)責(zé)返回有效的值捆昏。在寫入訪問(wèn)器屬性時(shí)赚楚,會(huì)調(diào)用setter
函數(shù)并傳入新值,這個(gè)函數(shù)負(fù)責(zé)決定如何處理數(shù)據(jù)屡立。同樣的直晨,訪問(wèn)器屬性除了同數(shù)據(jù)屬性一樣,有[[Configurable]]
和[[Enumerable]]
這兩個(gè)特性外膨俐,還有兩個(gè)特性:
[[Get]]
:在讀取屬性時(shí)調(diào)用的函數(shù)勇皇。默認(rèn)值為undefined
[[Set]]
:在寫入屬性時(shí)調(diào)用的函數(shù)。默認(rèn)值為undefined
不過(guò)焚刺,訪問(wèn)器屬性不能直接定義敛摘,必須使用Object.defineProperty()方法來(lái)定義。
var person = {
year: 4,
edition: 1
}
Object.defineProperty(person, 'year', {
get: function() {
return this.year
},
set: function(newValue) {
if (newValue > 4) {
this.year = newValue
this.edition += newValue - 4
}
}
})
person.year = 5
alert(person.edition) // 2
如上例子所示:每次訪問(wèn)year
屬性值乳愉,都會(huì)調(diào)用year
屬性本身的一個(gè)get
函數(shù)兄淫,這個(gè)函數(shù)負(fù)責(zé)把year
屬性值返回出去屯远。而如果要修改year
屬性值,則會(huì)調(diào)用year
屬性本身的一個(gè)set
函數(shù)捕虽,而修改的值則會(huì)當(dāng)做參數(shù)傳入這個(gè)set
函數(shù)慨丐,然后在set
函數(shù)內(nèi)部,做相應(yīng)的邏輯處理泄私。
不過(guò)由于標(biāo)準(zhǔn)問(wèn)題房揭,F(xiàn)ireFox也有一套對(duì)應(yīng)的方法,defineGetter()和defineSetter()晌端。用這兩個(gè)方法重寫上面的例子可以這樣寫:
let person = {
year: 4,
edition: 1
}
person._defineGetter_('year', function() {
return this.year
})
person._defineSetter_('year', function(newValue) {
if(newValue > 4) {
this.year = newValue
this.edition += newValue - 4
}
})
定義多個(gè)屬性
可以用Object.defineProperties()
方法定義多個(gè)屬性捅暴。此方法接收兩個(gè)參數(shù),第一個(gè)是要添加或修改其屬性的對(duì)象咧纠,第二個(gè)對(duì)象的屬性與第一個(gè)對(duì)象中要添加或修改的屬性一一對(duì)應(yīng)蓬痒,也是一個(gè)描述符對(duì)象。
例如:
let person = {}
Object.defineProperties(person, {
year: {
writable: true,
value: 4
},
edition: {
writable: true,
value: 1
},
_year: {
get: function() {
return this.year
},
set: function(newValue) {
if(newValue > 4) {
this._yaer = newValue
this.edition += newValue - 4
}
}
}
})
讀取屬性的特性
使用Object.getOwnPropertyDescriptor()
方法可以讀取屬性對(duì)應(yīng)的特性漆羔。此方法接收兩個(gè)參數(shù)梧奢。第一個(gè)是屬性所在的對(duì)象,第二個(gè)是要讀取其描述符的屬性名稱钧椰。返回值是一個(gè)對(duì)象粹断,如果是數(shù)據(jù)屬性,則返回的對(duì)象包括configurable
,enumerable
,writable
和value
這四個(gè)屬性嫡霞。如果是訪問(wèn)器屬性,則返回的對(duì)象包括configurable
,enumerable
,get
和set
這四個(gè)屬性希柿。
如下例:
let book = {}
Object.getOwnPropertyDescriptor(book, {
year: {
value: 4
},
edition: {
value: 1
},
_year: {
get: function() {
return this.year
},
set: function(newValue) {
if(newValue > 4) {
this.year = newValue
this.edition += newValue - 4
}
}
}
})
let obj = Object.getOwnPropertyDescriptor(person, 'year')
console.log(obj.value) // 4
console.log(obj.configurable) // false