オブジェクトの扱いに一歩踏み込む為、Object.defineProperty()を使ってみた

image.png (59.9 kB)

TOC

はじめに

変数を定義する際、再代入を行わない時、constを使って定義するかと思います。

const string = 'Hello!'

しかし、オブジェクトをconstで定義しても、プロパティに対する変更は可能です。

const obj = {
  a: 1,
}
obj.a = 2
console.log(ogj.a) // => 2

constはあくまで再代入不可なだけあって、プロパティの書き換えなどに対する制限は行いません。 では、プロパティを書き換えを防ぎたい時はどうすればいいでしょうか? そういう時に利用する1つの方法として、Object.defineProperty()があります。

Object.defineProperty()

Object.defineProperty()とはどのようなメソッドなのか見てみましょう。 オブジェクトのプロパティは、値以外に以下3つの特別なフラグを持っています。

  • writable: Boolean / trueなら変更可能
  • enumerable: Boolean / trueなら列挙可能
  • configurable : Boolean / trueなら再定義可能

これらを踏まえ、Object.defineProperty()を使ってプロパティを定義するとこのような形になります。

const obj = {}

Object.defineProperty(obj, 'a', {
  value: 1,
  writable: true,
  enumerable: true,
  configurable: true,
})

writable

では、ひとつひとつのフラグがどのような意味を持っているか見ていきたいと思います。 まず初めにwritableフラグですが、falseに設定すると読み取り専用となり、Object.defineProperty()を再度利用しない限り変更を行う事ができません。

const obj = {}

Object.defineProperty(obj, 'a', {
  value: 1,
  writable: false, // 変更できないよう制限
  enumerable: true,
  configurable: true,
})

obj.a = 2
console.log(obj.a) // => 1 ... 代入しても値は書き換かわらない

Object.defineProperty(obj, 'a', {
  value: 2,
})

console.log(obj.a) // => 2 ... Object.defineProperty()経由では値の変更が可能

enumerable

次にenumerableフラグですが、こちらは列挙可能かどうか設定を行います。 列挙とはObject.keys()for...inなどで表示されるものを指します。

const obj = {}

Object.defineProperty(obj, 'a', {
  value: 1,
  enumerable: false,
})

console.log(Object.keys(obj)) // => [] ... 列挙されない

configurable

最後にconfigurableフラグですが、こちらはwritableフラグと違い、falseに設定すると、Object.defineProperty()を利用しても削除したり変更したりすることができなくなります。

const obj = {}

Object.defineProperty(obj, 'a', {
  value: 1,
  writable: false,
  enumerable: true,
  configurable: false,
})

obj.a = 2

Object.defineProperty(obj, 'a', {
  value: 2,
  writable: false,
  enumerable: true,
  configurable: false,
}) // Error ... writableフラグの時とは違い値の変更ができない

Object.getOwnPropertyDescriptor()

では次にオブジェクトリテラル({})で定義したオブジェクトに、どのようなフラグが設定されているか確認してみます。 プロパティに設定されているフラグの確認には、Object.getOwnPropertyDescriptor()を使用します。

const obj = {
  a: 1,
};

console.log(Object.getOwnPropertyDescriptor(obj, 'a'))
// => {value: 1, writable: true, enumerable: true, configurable: true}

このようにオブジェクトリテラルで定義した場合すべての値がtrueで設定されている事がわかります。

Object.defineProperties()

Object.defineProperty()は1回につき1つのプロパティしか設定できません。 複数のプロパティを設定したい場合はObject.defineProperties()を使います。

const obj = {}

Object.defineProperties(obj, {
  'a': {
    value: 1,
    writable: false,
    enumerable: true,
    configurable: true,
  },
  'b': {
    value: 1,
    writable: true,
    enumerable: false,
    configurable: true,
  },
  'c': {},
  'd': {},
})

まとめ

いつも何気なく利用しているオブジェクトですが、中このようなフラグ郡が設定されていました。 リテラル記法以外の定義方法を理解し、より良いコードを書けるようになりたいなと思いました。

CONTACT
© 2023, Kakkiii All Rights Reserved.