Object.defineProperty()とは
あるオブジェクトに新しいプロパティを直接定義したり、オブジェクトの既存のプロパティを変更したりして、そのオブジェクトを返します。(出典:MDN)
と言っても何がいい害かわからないので、実際にコードを書いてみることにする。
書き方
const obj = {
age: 12
}
const descriptor = {
value: "john",
writable: true
}
Object.defineProperty(obj, 'name', descriptor)
console.log(obj.name) // "john"
ほぼmdnでの例文で数字を変えただけであるが、今何が起きているのかを一つつづ説明すると...
① オブジェクトの宣言
const obj = {
age: 12
}
ここではageというkeyを持つオブジェクトを宣言した。
ここにnameというkeyを持つプロパティを追加するにはどうすれば良いか。
その時使うのがdefineProperty()である。
言葉そのどおり、プロパティを宣言するメソッドである。
② defineProperty()の引数を入れる
Object.defineProperty(<対象となるオブジェクト>, <プロパティ名>, <プロパティの詳細>)
引数は3つまで入れることができ、それぞれ「対象となるオブジェクト」、「プロパティ名」、「プロパティの詳細」を入れることができて、全て必須である。
なおこのメソッドの返り値は対象となるオブジェクトそのものとなる。
descriptorについて
const descriptor = {
value: "john",
writable: true,
enumerable: false,
configurable: true
}
descriptorは例文に書いてあるvaleやwritable以外にenumerableとconfigurableがあり、value以外は全てbooleanになる。
書く項目については以下の通りである。
value
プロパティに対する値を意味する。
例文では"name"というプロパティに"john"という値を指定
writable
ここがfalseの場合、該当のプロパティはreadonlyになる
enumerable
ここがfalseの場合、該当のプロパティをループ(for文やObject.keys()を利用すること)させることができない
configurable
ここがfalseの場合、該当のプロパティを再定義することができない
Getterの設定
definePropertyではオブジェクトにgetterとsetterを設定することもできる。
まず、getterの設定方法は以下の通りである。
type NameObj = {
firstName: string
lastName: string
fullName?: string
}
const user = {
firstName: "Steven",
lastName: "Spielberg"
}
const myUser:NameObj = Object.defineProperty<NameObj>(user, 'fullName' , {
get: () => `${user.firstName} ${user.lastName}`,
})
console.log(myUser.fullName) // "Steven Spielberg"
上記では、NameObj
というオブジェクトにdefineProperty
を用いてgetterプロパティを追加した例である。
defineProperty
の第一引数に渡されたオブジェクトにfullName
というgetterを追加することにより、firstName
とlastName
を一つにしたfullName
を出力することができる。同じやり方でsetterをつけることも可能である。
type NameObj = {
firstName: string
lastName: string
fullName?: string
}
const user = {
firstName: "Steven",
lastName: "Spielberg"
}
const myUser:NameObj = Object.defineProperty<NameObj>(user, 'fullName' , {
get: () => `${user.firstName} ${user.lastName}`,
set: (value: string) => {
[user.firstName, user.lastName] = value.split(' ')
}
})
myUser.fullName = 'James Cameron'
console.log(myUser.fullName)
違いはset
プロパティを追加し、分割代入でfirstName
とlastName
を代入していることがわかる。
そして、getterプロパティを使って、代入された値を取り出している仕組みである。
こうすることで、値の保持と管理を分けることが可能である。