0
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のプロパティ定義方法

Last updated at Posted at 2022-08-12

はじめに

JavaScriptのプロパティ定義には以下のような方法があります。

const o1 = {
  prop: 'hoge',
  propFn: () => 10000,
};

const o2 = new Object();
o2.prop = 'hoge';
o2['propFn'] = () => 10000;

そしてこれら定義されたメンバはfor...inによって列挙することができます。

for (const property in o1) {
  console.log(`${property}: ${o1[property]}`);
}

// expected output:
// prop: hoge
// propFn: () => 10000

for (const property in o2) {
  console.log(`${property}: ${o2[property]}`);
}

// expected output:
// prop: hoge
// propFn: () => 10000

ふー! これでObjectのプロパティの定義方法と一覧を取得できることがわかりました! それでは。

……とはいかないですよね。そもそもここはまだ「はじめに」です。
for...inにはのっけから気になる記述があります。

for...in 文は、キーが文字列であるオブジェクトの列挙可能プロパティすべてに対して、継承された列挙可能プロパティも含めて反復処理を行います (Symbol がキーになったものは無視します)

オブジェクトの 列挙可能 プロパティすべて???

列挙可能・列挙不可能

『列挙可能プロパティ』 はリンクになっているため、リンク先を見てみます。するとプロパティの列挙可能性と所有権にたどり着きます。
検出の項目にはObject.prototype.propertyIsEnumerable()があるためとりあえず見てみましょう。

このページに書かれていることを引用すると以下の通りです。

  • コード
obj.propertyIsEnumerable(
  /** 調べたいプロパティの名前 */
) => /** 指定されたプロパティが列挙可能であり、かつオブジェクト自身のプロパティであるかどうか */
  • 解説

すべてのオブジェクトは propertyIsEnumerable メソッドを持っています。このメソッドはあるオブジェクトのプロパティが、プロトタイプチェーンを通じて継承されたプロパティを除いて for...in ループで列挙可能かどうかを特定することができます。もしオブジェクトが指定されたプロパティを持っていない場合、このメソッドはfalseを返します。

なるほど。 列挙されない プロパティを定義できるんですね。これは驚いた。
でも確かに、Objectにはパッと思いつくだけでもObject.prototype.toString()Object.prototype.constructor
が生えているのに列挙されていませんね。気づかなかっただけでずっとそこにいたわけです。
でもどうやって定義するのでしょうか?

列挙不可能なプロパティを定義

元のページに戻ると以下の記述があります。

Object.definePropertyで追加したプロパティはデフォルトで列挙可能性がfalseになります

Object.defineProperty()でもプロパティを追加できるのか。
見てみましょう。使い方は以下の通り。

/**
 * @param obj プロパティを定義するオブジェクト
 * @param prop 定義または変更するプロパティの名前またはSymbol
 * @param descriptor 定義または変更するプロパティの記述子
 * @return この関数に渡されたオブジェクト
 */
Object.defineProperty(obj, prop, descriptor)

obj は対象のオブジェクト、 prop はキーに該当するもので間違い無いでしょう。では descriptor は?
それは解説に書かれています。
そのまま引用します。

  • configurable

trueである場合のみ、この種の記述子を変更することや、対応するオブジェクトからプロパティを削除することができます。 既定値はfalseです。

  • enumerable

trueである場合のみ、このプロパティは対応するオブジェクトでのプロパティ列挙に現れます。 既定値はfalseです。

データ記述子は以下のオプションキーも持ちます。

  • value

プロパティに関連づけられた値です。有効なJavaScriptの値(number, object, functionなど) である必要があります。
既定値はundefinedです。

  • writable

trueである場合のみ、プロパティに関連づけられた値は代入演算子で変更することができます。既定値はfalseです。

なるほどなるほど。列挙する・しないはenumerableで決めることができるんですね。
また加えてdeleteできるかどうかや書き換えることができるかどうかなども設定できるとは。いやはや恐れ入りました。
確かに書き換えたり削除したりすることができない値もありますもんね。

delete document.location  // false

参考: delete演算子

オブジェクトのプロパティ定義方法についてを修めるつもりがプロパティの種類までわかってしまいました。棚ボタです!

ちなみにですが、このdescriptorですが、TypeScriptのDecoratorの文脈でも出てきます。(参考)

おわりに

検出の項目にはObject.prototype.propertyIsEnumerable()があるためとりあえず見てみましょう。

の部分にやや無理があることは承知していますが、持っていきたい方向があったため流れを優先しました。

0
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
0
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?