1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

javascriptのObject.defineProperty()について

Last updated at Posted at 2022-10-12

Object.defineProperty()とは

あるオブジェクトに新しいプロパティを直接定義したり、オブジェクトの既存のプロパティを変更したりして、そのオブジェクトを返します。(出典:MDN

と言っても何がいい害かわからないので、実際にコードを書いてみることにする。

書き方

javascript
const obj = {
    age: 12
}
const descriptor = {
    value: "john",
    writable: true
}

Object.defineProperty(obj, 'name', descriptor)
console.log(obj.name) // "john" 

ほぼmdnでの例文で数字を変えただけであるが、今何が起きているのかを一つつづ説明すると...

① オブジェクトの宣言

javascript
const obj = {
    age: 12
}

ここではageというkeyを持つオブジェクトを宣言した。
ここにnameというkeyを持つプロパティを追加するにはどうすれば良いか。
その時使うのがdefineProperty()である。
言葉そのどおり、プロパティを宣言するメソッドである。

② defineProperty()の引数を入れる

javascript
Object.defineProperty(<対象となるオブジェクト>, <プロパティ名>, <プロパティの詳細>)

引数は3つまで入れることができ、それぞれ「対象となるオブジェクト」、「プロパティ名」、「プロパティの詳細」を入れることができて、全て必須である。
なおこのメソッドの返り値は対象となるオブジェクトそのものとなる。

descriptorについて

javascript
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の設定方法は以下の通りである。

typescript
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を追加することにより、firstNamelastNameを一つにしたfullNameを出力することができる。同じやり方でsetterをつけることも可能である。

typescript
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プロパティを追加し、分割代入でfirstNamelastNameを代入していることがわかる。
そして、getterプロパティを使って、代入された値を取り出している仕組みである。
こうすることで、値の保持と管理を分けることが可能である。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?