JavaScriptオブジェクトの反復処理とプロトタイプ操作

JavaScriptの長い歴史の中で、オブジェクトのプロパティを反復処理することは常に課題でした。ECMAScript 2017では、オブジェクトの内容をシリアライズされた、そして重要なことに反復可能な形式に変換するための2つの静的メソッドが追加されました。これらの静的メソッドであるObject.values()とObject.entries()はオブジェクトを受け取り、その内容の配列を返します。Object.values()はオブジェクトの値の配列を返し、Object.entries()はキーと値のペアの配列を返します。

以下の例はこれらのメソッドの使用方法を示しています:

const sampleObj = { 
  identifier: 'value', 
  numericProp: 42, 
  objectProp: { nested: true } 
}; 
console.log(Object.values(sampleObj));
// ["value", 42, { nested: true }] 
console.log(Object.entries(sampleObj)); 
// [["identifier", "value"], ["numericProp", 42], ["objectProp", { nested: true }]] 

これらのメソッドはオブジェクトの浅いコピーを実行します:

const dataObject = { 
  reference: { data: 'test' } 
}; 
console.log(Object.values(dataObject)[0] === dataObject.reference);
// true 
console.log(Object.entries(dataObject)[0][1] === dataObject.reference); 
// true

シンボルプロパティは無視される点に注意してください:

const uniqueSymbol = Symbol('description');
const symbolObj = { 
  [uniqueSymbol]: 'symbolValue' 
}; 
console.log(Object.values(symbolObj)); 
// [] 
console.log(Object.entries(symbolObj)); 
// []

プロトタイプの代替構文について、以前の例ではプロパティやメソッドを定義するたびに毎回プロトタイプ全体を再記述していました。コードの冗長性を減らし、プロトタイプ機能を視覚的にカプセル化するために、オブジェクトリテラルを使用してプロトタイプ全体を一度に再定義するのが一般的です:

function UserProfile() {}
UserProfile.prototype = {
  name: "田中太郎",
  age: 30,
  occupation: "フロントエンド開発者",
  introduce() {
    console.log(`私の名前は${this.name}です。`);
  }
};

この方法には一つ問題があります。このようにプロトタイプを再定義すると、UserProfile.prototypeのconstructorプロパティがUserProfileを指さなくなります。関数が作成されるとき、そのプロトタイプオブジェクトも同時に作成され、constructorプロパティが自動的に設定されます。上記の方法ではデフォルトのプロトタイプオブジェクトを完全に置き換えてしまうため、constructorプロパティは全く異なるオブジェクト(Objectコンストラクタ)を指すようになります。

const user = new UserProfile();
console.log(user instanceof Object); // true 
console.log(user instanceof UserProfile); // true
console.log(user.constructor == UserProfile); // false 
console.log(user.constructor == Object); // true

instanceof演算子は依然として正しく動作しますが、constructorプロパティを使って型を識別することはできません。constructorの値が重要な場合は、プロトタイプオブジェクトを再定義する際に明示的に設定できます:

UserProfile.prototype = {
  constructor: UserProfile,
  name: "田中太郎",
  age: 30,
  occupation: "フロントエンド開発者",
  introduce() {
    console.log(`私の名前は${this.name}です。`);
  }
};

この方法でconstructorプロパティを復元すると、[[Enumerable]]属性がtrueのプロパティが作成されます。一方、ネイティブのconstructorプロパティはデフォルトで列挙不可です。ECMAScriptに準拠したJavaScriptエンジンを使用している場合は、Object.defineProperty()メソッドを使用してconstructorプロパティを定義する方が適切です:

UserProfile.prototype = {
  name: "田中太郎",
  age: 30,
  occupation: "フロントエンド開発者",
  introduce() {
    console.log(`私の名前は${this.name}です。`);
  }
}; 
// constructorプロパティを復元
Object.defineProperty(UserProfile.prototype, "constructor", { 
  enumerable: false,
  value: UserProfile
});

タグ: javascript オブジェクト プロトタイプ ECMAScript Object.values

5月24日 02:27 投稿