什么是屬性晌砾?
屬性是對象的成員,由名/值對組成担忧,值可以是單純的原始數(shù)據(jù)類型芹缔,也可以是對象、方法一樣的引用數(shù)據(jù)類型瓶盛。
每個屬性(property)上還有一些特性(attribute),這些特性決定了這個屬性是存取器屬性還是數(shù)據(jù)屬性最欠。
數(shù)據(jù)屬性
數(shù)據(jù)屬性有四個特性,分別是值(value)惩猫、可寫性(writable)芝硬、可枚舉性(enumerable)和可配置性(configurable)
- value:屬性的值
- writable:布爾值,默認(rèn)為true
- 為false時(shí)該屬性的值無法被設(shè)置
- enumerable:布爾值轧房,默認(rèn)為true
- 為false時(shí)無法被for in 循環(huán)枚舉
- configurable:布爾值拌阴,默認(rèn)為true
- 為false時(shí)無法使用delete刪除
- 為false時(shí)無法成功配置屬性的特性
存取器屬性
存取器屬性和數(shù)據(jù)屬性的區(qū)別就是存取器屬性的值會被一個或兩個方法替代,這個兩個方法是getter和setter奶镶。
存取器屬性的四個特性就是讀(get)迟赃、寫(set)、可枚舉(enumerable)和可配置(configurable)
- get:一個方法厂镇,用來獲取該屬性的值纤壁,決定了這個存取器是否可讀,當(dāng)get不存在時(shí)捺信,訪問屬性返回的都是undefined
- set:一個方法酌媒,用來設(shè)置該屬性的值,決定了這個存取器是否可寫,當(dāng)set不存在時(shí)馍佑,屬性的值無法設(shè)置
- enumerable:布爾值斋否,默認(rèn)為true
- 為false時(shí)無法被for in 循環(huán)枚舉
- configurable:布爾值梨水,默認(rèn)為true
- 為false時(shí)無法使用delete刪除
- 為false時(shí)無法成功配置屬性的特性拭荤,也就是說此屬性為false的數(shù)據(jù)屬性不能被重新定義為存取器屬性
屬性特性的設(shè)置
上面簡單介紹了數(shù)據(jù)屬性和存取器屬性的一些特性,那么要修改這些特性應(yīng)該怎么做呢疫诽?在ES5中有Object.defineProperty()和Object.defineProperties()兩個方法能直接定義或修改屬性的特性舅世。
- Object.defineProperty(obj, name, descriptors)
- obj:將在其上創(chuàng)建或配置屬性的對象
- name:將創(chuàng)建或配置的屬性的名字
- descriptors:一個屬性描述符對象,描述要創(chuàng)建的新屬性或?qū)ΜF(xiàn)有屬性的修改
- 返回值:對象obj
var obj = {}
Object.defineProperty(obj, 'a', {
configurable: true,
enumerable: true,
writable: true,
value: 123
})
上面這個例子在obj上創(chuàng)建了一個屬性a奇徒,并且配置了四個特性雏亚。但如果obj上本來就有屬性a的話,就只會對
配置的這些特性進(jìn)行覆蓋(前提是a上的configurable這個特性為true)
- Object.defineProperties(obj, descriptors)
- obj: 要在其上創(chuàng)建或配置屬性的對象
- descriptors:將屬性名映射到屬性描述符的對象
- 返回值:對象obj
var obj = {}
var bbb = 'b'
Object.defineProperties(obj, {
a: {
value: 12,
writable: true,
enumerable: true,
configurable: true
},
[bbb]: {
value: 13,
writable: true,
enumerable: true,
configurable: true
}
})
上面這個例子在obj上創(chuàng)建了屬性a和b摩钙,并且我們知道了可以用變量來替代需要定義的屬性名
通過上面兩個例子我們知道了有兩個方法能給屬性設(shè)置特性罢低,數(shù)據(jù)屬性的四個特性沒什么特別的,我們看看存取器屬性的特性應(yīng)該怎么設(shè)置胖笛。
var obj = {
a: 1,
get c() {
return this.a * 2
},
set c(newVal) {
this.a = newVal / 2
}
}
這個例子中网持,在obj中創(chuàng)建了一個數(shù)據(jù)屬性a和存取器屬性c,當(dāng)獲取或設(shè)置c的時(shí)候长踊,就會進(jìn)入相應(yīng)的函數(shù)運(yùn)行功舀,注意這里的get和set后面沒有冒號
var obj = {
a: 12
}
var val = obj.a
Object.defineProperty(obj, 'a', {
configurable: true,
enumerable: true,
get: function() {
console.log('訪問了屬性a')
return val
},
set: function(newVal) {
console.log('設(shè)置了屬性a')
val = newVal
}
})
這個例子展示了用defineProperty怎么創(chuàng)建存取器屬性,和直接創(chuàng)建的區(qū)別就是這里的get和set后面有冒號身弊,方法中this是指向Object.defineProperty的第一個參數(shù)obj的辟汰,這點(diǎn)和之前的例子一摸一樣。
最后阱佛,還有一個獲取屬性特性的函數(shù)getOwnPropertyDescriptor()
- Object.getOwnPropertyDescriptor(obj, name)
- obj:待查詢其屬性特性的對象
- name:待查詢的屬性名(或數(shù)組元素的索引)
- 返回值:指定對象指定屬性的一個屬性描述符對象帖汞,如果不存在指定屬性則返回undefined
var obj = {
a: 12
}
Object.defineProperty(obj, 'a', {
writable: false
})
console.log(Object.getOwnPropertyDescriptor(obj, 'a')) // {value: 12, writable: false, enumerable: true, configurable: true}
var obj = {
get a(){
return 1
}
}
console.log(Object.getOwnPropertyDescriptor(obj, 'a')) // {get: ?, set: undefined, enumerable: true, configurable: true}