本文快速導覽 :
- 物件屬性設定
- 單一屬性設定
Object.definedProperty(物件, 屬性)
- 多個屬性設定
Object.defineProperties(物件, { 屬性:{}, 屬性2:{}})
- 單一屬性設定
- 物件設定方法
- 防止物件屬性擴充
Object.preventExtensions(物件)
- 封裝物件
Object.seal
- 凍結物件
Object.freeze
- 防止物件屬性擴充
- 檢查物件設定
- 回傳物件屬性設定
Object.getOwnPropertyDescriptor(物件, 屬性)
- 回傳多個物件屬性設定
Object.getOwnPropertyDescriptors(物件, 屬性1, 屬性2)
- 物件屬性可否被擴充
Object.isExtensible(物件)
(true or fasle) - 物件是否被封裝
Object.isSealed(物件)
- 物件是否被凍結
Object.isFrozen(物件)
- 列舉物件屬性
Object.keys(物件)
- 只回傳可被列舉的屬性名稱
- 與
for in
一致 - 回傳陣列
[屬性1, 屬性2, ...]
- 列舉物件屬性
Object.getOwnPropertyNames(物件)
- 不管是否無法被列舉,都會顯示其屬性名稱
- 回傳陣列
[屬性1, 屬性2, ...]
- 回傳物件屬性設定
- 賦值運算不使用額外函式
- Getter 與 Setter
- 錯誤設定
(快速導覽包含一些本文未使用的方法,以方便日後搜尋)
物件屬性設定
在原型鏈中,我們會用 某函式.prototype.要新增的屬性名稱
在原生原型上新增共用的方法或值,但新增後使用 console.log()
卻找不到它,這是怎麼一回事? 原因在於它的屬性被 Object.definedProperty
設定了。
單一屬性設定 Object.definedProperty
可設定特徵名稱 | 功能 |
---|---|
value | 值 |
writable | 可否寫入 |
configurable | 可否被刪除 |
enumerable | 可否被列舉 |
要注意的是,Object.definedProperty
只能針對當下的物件屬性作設定,若物件內屬性值也為物件,還是可以被寫入。
1 | /* 物件屬性設定 */ |
多個屬性特徵設定 Object.defineProperties
1 | /* 一次修改多屬性設定 */ |
物件設定方法
除了可以設定物件內屬性,也可以針對物件本身去設定,像是 :
Object.preventExtensions
- 防止擴充 / 無法新增屬性,但無法針對巢狀屬性禁止
Object.seal
- 封裝
Object.Freeze
- 凍結
Object.preventExtensions
- 防止該物件屬性被擴充,但它無法對巢狀物件屬性禁止
- 屬性可以被刪除
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25var person = {
a:1,
b:2,
c:3
}
Object.preventExtensions(person)
delete person.c
// 回傳布林值,是否可被擴充
console.log('是否可以被擴充:'+ Object.isExtensible(person))
// 檢查物件屬性設定
console.log(Object.getOwnPropertyDescriptor(person, 'a'))
// Object {
// configurable: true,
// enumerable: true,
// value: 1,
// writable: true
// }
console.log(person)
// Object {
// a: 1,
// b: 2
// }
Object.seal
- 不能調整屬性特徵
- 可以調整目前屬性值
- 物件屬性會被加上 preventExtensions
- 無法新增刪除屬性
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33var person = {
a:1,
b:2,
c:3
}
Object.seal(person)
person.a = 1000
person.d = 10
delete person.b
Object.defineProperty(person, 'b', {
writable: false
})
person.b = 2000
// 回傳布林值,是否被封裝
console.log('是否被封裝:'+ Object.isSealed(person))
// true
// 檢查物件屬性設定
console.log(Object.getOwnPropertyDescriptor(person, 'a'))
// Object {
// configurable: false,
// enumerable: true,
// value: 1000,
// writable: true
// }
console.log(person)
// Object {
// a: 1000,
// b: 2000,
// c: 3
// }
Object.freeze
物件使用 Object.Freeze
凍結後,就無法對它修改屬性設定,否則會報錯。
1 | var person = { |
賦值運算不使用額外函式
物件屬性還有兩個特徵可以設定,分別是 Getter 與 Setter,以下就來看看它們怎麼運作。
Getter 與 Setter
- Getter,取值
- 使用 console.log()檢查時,狀態為
...
,當點開時才會正確取值
- 使用 console.log()檢查時,狀態為
- Setter,存值
- 必須要有傳入參數,否則報錯
- console.log()、return 不會有任何作用
1
2
3
4
5
6
7
8
9
10
11
12
13
14var a = {
array: [1, 2, 3],
get getData(){
return this.array
},
set addData(a){
this.array.push(a)
return 1
},
}
a.addData = "99"
a.addData = "100"
console.log(a)
使用 Object.defineProperty,設定 Getter、Setter
若有一個已知的物件其屬性未設定 Getter、Setter,可以使用 defineProperty來設定。透過這個方式設定時,Getter、Setter的預設為不可列舉也不可被刪除。以下範例使用了 :
- 多個屬性特徵設定
- Getter 與 Setter
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38// 收入來源有股票與工作
// 將它們分別設定 Getter 與 Setter
var sourceofIncome = {
money: 0,
stock: null,
work: null
}
Object.defineProperties(sourceofIncome, {
money: {
configurable: false
},
stock: {
set: function (money){
this.__stock__ = money
this.money += money
},
get: function (){
return `股票賺了: ${this.__stock__},現在有: ${this.money}`
}
},
work: {
set: function (money){
this.__work__ = money
this.money += money
},
get: function (){
return `股票賺了: ${this.__work__},現在有: ${this.money}`
}
},
})
sourceofIncome.stock = 20000
sourceofIncome.work = 50000
// 若分段顯示就會是分段的,現在金額顯示為累計過的
console.log(sourceofIncome.stock)
console.log(sourceofIncome.work)
console.log(sourceofIncome.money) - 若要設定屬性值,可以針對屬性再多一個屬性,像是
this.__work__
,否則指向自己,會變成無限循環。 - 取用屬性時,可以同時做很多事,不用再額外寫函式傳參數進去。
錯誤設定
設定過程中可能會遇到以下問題 :
Maximum call stack size exceeded
- Getter 與 Setter 不能指向自己,否則會造成無限循環。
Invalid property descriptor. Cannot both specify accessors and a value or writable attribute, #<Object>
- 因為屬性特徵不相容
- 資料描述器 ( data descriptor ) : value、writable與其他
- 存取器描述器 ( accessor descriptor ) : get 與 set
- 因為屬性特徵不相容