對象屬性形貌符
當他人對你說起對象屬性形貌符,可以會蒙逼。而假如說起對象屬性的 get/set 要領就秒懂了,規範形貌和習氣表述在這裡有些差別,然則指向的是同一個觀點所觸及的東西。對象屬性形貌符
在編程實踐中是經由過程 Object 對象的defineProperty
要領暴露給我們。所以搞清楚Object.defineProperty
是明白對象屬性形貌符
的唯一門路。
Object.defineProperty
, define Property 翻譯成中文就是定義屬性,望文生義就是為對象定義或修正屬性的細節,即經由過程屬性形貌符來定義屬性讀寫的細節。運用該要領許可準確增加或修正對象的屬性,熟習 vue 的朋儕對 defineProperty 因該不生疏:
Object.defineProperty(obj, prop, descriptor)
defineProperty
接收3個參數, obj 示意要修正或許定義屬性的對象,prop 是要定義或許修正屬性的稱號, descriptor
屬性形貌符用於定義該屬性的特徵。
descriptor 是一個對象,對象里的屬性形貌符有兩種範例:數據形貌符和存取形貌符。
數據形貌符是一個具有值的屬性,該值多是可寫的,也可以不是可寫的。
存取形貌符是由getter-setter函數對形貌的屬性。形貌符必需是這兩種情勢之一;不能同時是二者。
數據形貌符和存取形貌符均具有一下可選鍵值(特徵):
- configurable: 假如為 false,則任何嘗試刪除目的屬性或修正屬性以下特徵(writable, configurable, enumerable)的行動將被無效化,默許值為 false。
- enumerable: 是否能羅列。也就是是否能被for-in遍歷。默許值為 false
- writable: 是否能修正值。默以為 false
- value: 該屬性的詳細值是多少。默以為 undefined
存取形貌符:
- get: 目的屬性被接見就會調回此要領,並將此要領的運算效果返回用戶。默以為 undefined
- set: 目的屬性被賦值,就會調回此要領。默以為 undefined
形貌符可同時具有的鍵值:
configurable | enumerable | value | writable | get | set | |
---|---|---|---|---|---|---|
數據形貌符 | Yes | Yes | Yes | Yes | No | No |
存取形貌符 | Yes | Yes | No | No | Yes | Yes |
假如一個形貌符不具有value,writable,get 和 set 恣意一個關鍵字,那末它將被以為是一個數據形貌符。假如一個形貌符同時有(value或writable)和(get或set)關鍵字,將會發生一個非常。所以 value、writable 與 get/set 不能同時設置。
var obj = {}
obj.a = 123
Object.defineProperty(obj, "newDataProperty", {
value: 101, // 設置值
writable: true, // 值可以被修正
enumerable: true, // 可以被羅列
configurable: true // 屬性可以被刪除、特徵可以修正
})
上面給對象 obj 增加一個新屬性 ‘newDataProperty’,而且設置了屬性的特徵。
在ES5之前對象的屬性我們只能設置一個字面量值或許一個援用,在瀏覽器支撐Object.defineProperty
要領以後,就像給了我們一台顯微鏡,可以在更低的粒度層掌握屬性的行動和特徵:定義屬性的可接見行、值的讀寫劃定規矩等。
假如對象中不存在指定的屬性,Object.defineProperty()
會建立這個屬性。假如屬性已存在,Object.defineProperty()
將嘗試依據形貌符中的值以及對象當前的設置來修正這個屬性。假如舊形貌符將其configurable
屬性設置為false
,則該屬性被以為是“不可設置的”,而且沒有屬性可以被轉變(除了單向轉變 writable 為 false)。當屬性不可設置時,不能在數據和接見器屬性範例之間切換。
形貌符中未顯現設置的特徵運用其默許值。
下面用幾個栗子來演示這些特徵的詳細表現:
configurable
let foo = {
a: 1
}
delete foo.a
Object.defineProperty(foo, 'b', {
value: 2, // 默許值為2
configurable: false // 不容許被刪除和修正
})
delete foo.b // 沒法刪除
foo.b = 999 // 沒法修正
console.log(foo.b) // 2
enumerable
let foo = {
a: 1,
b: 2,
c: 3
}
for (let i in foo) {
// a、b、c可以被羅列
console.log(`key: ${i}, value: ${foo[i]}`)
}
Object.defineProperty(foo, 'a', {
enumerable: false // 設置屬性不可以被羅列
})
for (let i in foo) {
// a沒有被羅列
console.log(`key: ${i}, value: ${foo[i]}`)
}
writable
let foo = {
a: 1
}
// 修正 foo.a 的值
foo.a = 2
console.log(foo.a) // 2
Object.defineProperty(foo, 'a', {
writable: false // 設置值不能被修正
})
// 嘗試修正 foo.a 的值
foo.a = 3 // 沒法修正
console.log(foo.a) // 2
value
let foo = {}
Object.defineProperty(foo, 'a', {
value: 1 // 設置屬性的值為 1
})
console.log(foo.a) // 1
get/set
let foo = {
a: 1
}
Object.defineProperty(foo, 'b', {
get: function () {
return `hi, ${this.value}`
},
set: function (value) {
this.a = value // 將輸入值保存在同對象下屬性 a 里
this.value = value + 1
}
})
console.log(foo.b) // 'hi, undefined'
foo.b = 1
console.log(foo.a) // 1
console.log(foo.b) // hi, 2
注重: get沒有參數,set接收實參為當前設置的值.。在get、set函數內部可以經由過程this.value
接見value
特徵,從而經由過程該特徵來獵取或許着設置屬性的值。get/set 常用於值依靠內部數據的場所。須要只管同時設置get、set。假如僅僅只設置了get,那末我們將沒法設置該屬性值。假如僅僅只設置了set,我們也沒法讀取該屬性的值。
Object.defineProperty
只能設置一個屬性的形貌符,當須要設置多個屬性形貌符時可以運用Object.defineProperties
:
let foo = {}
Object.defineProperties(foo, {
a: {
value: 1,
configurable: true
},
b: {
get: function() {
return this.value ? `hi, ${this.value}` : 0
},
set: function(value) {
this.value = value + 1
}
}
})
console.log(foo.a) // 1
console.log(foo.b) // 0
foo.b = 2
console.log(foo.b) // 'hi, 3'
我們可以經由過程Object.getOwnPropertyDescriptor
獵取某一屬性的特徵鳩合:
let foo = {
a: 1
}
Object.defineProperty(foo, 'a', {
value: 2, // 設置值為 2
writable: false, // 值不可修正
configurable: false // 設置屬性不可刪除,特徵不可修正
})
let fooDescripter = Object.getOwnPropertyDescriptor(foo, 'a')
console.log(fooDescripter)
// 獵取的特徵以下
// {
// configurable:false,
// enumerable:true,
// value:2,
// writable:false
// }
這裏須要注重,Object.defineProperty
建立一個對象的新屬性與修正一個已存在屬性的區分。建立一個新屬性默許形貌符的鍵值都是 false 或許 undefined。而修正一個已存在的屬性的形貌符時,假如之前沒有被設置過或過原始體式格局給對象增加的屬性,則屬性的 configurable、enumerable、writable 形貌符都默以為 true。詳細差別舉個例子細細體味:
let foo = {}
Object.defineProperty(foo, 'a', {
value: 2 // 設置值為 2
})
let fooDescripter = Object.getOwnPropertyDescriptor(foo, 'a')
console.log(fooDescripter)
// 獵取的特徵以下
// {
// configurable:false, // 不容許被刪除和修正
// enumerable: false, // 不能被羅列
// value:2,
// writable:false // 值不可修正
// }
變量 a 是經由過程 Object.defineProperty
要領建立的,默許一切屬性形貌符的值都為 false。 我們可以經由過程末了兩個代碼示例體味一下區分:enumerable
屬性形貌符在兩個例子中都沒有被事前設置,然則差別情況下的值不一樣。
原則上這個系列不會去講某個API,然則屬性形貌符
可以加深我們對 javascript 、框架底層的明白。