JS のオブジェクトリテラルの詳細な説明

JS のオブジェクトリテラルの詳細な説明

序文

ES6 より前では、JavaScript のオブジェクト リテラル (オブジェクト初期化子とも呼ばれます) は非常に基本的なものでした。次の 2 種類のプロパティを定義できます。

  • キーと値のペア {name1: value1}
  • ゲッター { get name(){..} } とセッター { set name(val){..}} を使用して計算されたプロパティ値
var myObject = {
  myString: '値 1',
  myNumber() を取得 {
    this._myNumber を返します。
  },
  myNumber(値)を設定する{
    this._myNumber = Number(値);
  },
};
myObject.myString; // => '値 1'
myObject.myNumber = '15';
myObject.myNumber; // => 15

js はプロトタイプベースの言語なので、すべてがオブジェクトです。 オブジェクトの作成、構成、プロトタイプへのアクセスに関しては、構築を容易にする言語を提供する必要があります。

オブジェクトを定義し、そのプロトタイプを設定することは一般的なタスクです。最善の方法は、オブジェクトリテラルの単一のステートメントでプロトタイプを直接設定することです。

残念ながら、リテラルの制限により、これを実現するための簡単な解決策は存在しません。プロトタイプを設定するには、オブジェクトリテラルと組み合わせて object.create() を使用する必要があります。

var myProto = {
  プロパティが存在する: 関数(名前) {
    これで名前を返します。
  }
};

var myNumbers = Object.create(myProto);
myNumbers['arrat'] = [1, 6, 7];
myNumbers.propertyExists('array'); // => true
myNumbers.propertyExists('collection'); // => false

この解決策は柔軟性が十分ではないと思います。 JS はプロトタイプベースですが、プロトタイプを使用してオブジェクトを作成するのはなぜ面倒なのでしょうか?

幸いなことに、JS も徐々に改善しています。 JS の多くの厄介な問題は段階的に解決されます。

この記事では、ES6 が上記の問題をどのように解決し、追加機能によってオブジェクトリテラルを改善するかを説明します。

  • オブジェクト構築時にプロトタイプを設定する
  • メソッド宣言
  • スーパーコール
  • 計算されたプロパティ名

1. オブジェクト構築にプロトタイプを設定する

ご存知のとおり、既存のオブジェクトのプロトタイプにアクセスする 1 つの方法は、ゲッター プロパティ __proto__ を使用することです。

var myObject = {
  名前: 'Hello World!',
};
myObject.__proto__; // => {}
myObject.__proto__.isPrototypeOf(myObject); // => true

myObject.__proto__ は、myObject のプロトタイプ オブジェクトを返します。

object.__proto__ をゲッター/セッターとして使用することは推奨されないことに注意してください。代替アプローチとしては、Object.getPrototypeOf() と Object.setPrototypeOf() の使用を検討する必要があります。

ES6 では、プロパティ名として __proto__ を使用し、{__proto__: protoObject} でプロトタイプを設定できます。

次に、__proto__ プロパティを使用してオブジェクトを初期化し、上記のコードを最適化します。

var myProto = {
  プロパティが存在する: 関数(名前) {
    これで名前を返します。
  },
};
var myNumbers = {
  __proto__: myProto、
  配列: [1, 6, 7],
};
myNumbers.propertyExists('array'); // => true
myNumbers.propertyExists('collection'); // => false

myNumbers オブジェクトは、特別なプロパティ名 proto とプロトタイプ myProto を使用して作成されます。今回は、上記の object.create() のような追加の関数を必要とせず、単一のステートメントで作成します。

ご覧のとおり、__proto__ を使用したコーディングはシンプルで、私は常にシンプルで明確なソリューションを好みます。

話題から外れた話をしましょう。 シンプルで柔軟なソリューションにこれほど多くの作業と設計が必要になるのは奇妙だと思います。解決策が単純なら、設計も簡単だと思われるかもしれません。しかし、逆もまた真なりです。

  • シンプルかつ明確にするのは複雑です
  • 複雑になって理解しにくくなるのは簡単です。

複雑すぎる、または使いにくいと思われる場合は、さらに改良する必要があるかもしれません。

1.1 __proto__ の使用における特殊なケース

__proto__ は単純に見えますが、知っておくべき特殊なケースがいくつかあります。

オブジェクトリテラルでは __proto__ を 1 回だけ使用できます。そうでない場合、JS はエラーを報告します。

varオブジェクト = {
  __proto__: {
    toString: 関数() {
      '[オブジェクト番号]' を返す
    }
  },
  数字: [1, 5, 89],
  __proto__: {
    toString: 関数() {
      '[オブジェクト ArrayOfNumbers]' を返します
    }
  }
};

上記の例では、オブジェクトリテラル内で __proto__ プロパティを 2 回使用していますが、これは許可されていません。この場合、エラーがスローされます: SyntaxError: オブジェクトリテラルでは重複する __proto__ フィールドは許可されません。

JS では、__proto__ プロパティの値として使用できるのはオブジェクトまたは null のみと制限されています。 プリミティブ型 (文字列、数値、ブール値) または undefined の使用は無視され、オブジェクトのプロトタイプは変更されません。

var obj未定義 = {
  __proto__: 未定義、
};
Object.getPrototypeOf(objUndefined); // => {}
var オブジェクト番号 = {
  __proto__: 15,
};
Object.getPrototypeOf(objNumber); // => {}

オブジェクトリテラルは、undefined と数値 15 を使用して __proto__ 値を設定します。 プロトタイプとして許可されるのはオブジェクトまたは null のみであるため、__proto__ 値は無視されますが、objUndefined と objNumber にはデフォルトのプロトタイプ (プレーンな JS オブジェクト {}) が保持されます。

もちろん、プリミティブ型を使用してオブジェクトのプロトタイプを設定しようとするのも奇妙です。

また、オブジェクトリテラルに '__proto__' { ['__proto__']: protoObj } と評価される文字列がある場合にも注意してください。 この方法で作成されたプロパティはオブジェクトのプロトタイプを変更せず、単にキー '__proto__' を持つ所有プロパティを作成します。

2. 簡略化されたメソッド定義

関数キーワードと : コロンを省略して、より短い構文を使用してオブジェクト リテラルでメソッドを宣言できます。 これは、短縮メソッド定義と呼ばれます。

次に、ショートカット メソッドを使用していくつかのメソッドを定義してみましょう。

var コレクション = {
  アイテム: [],
  追加(アイテム) {
    this.items.push(アイテム);
  },
  get(インデックス) {
    this.items[index]を返します。
  },
};
コレクション.add(15);
コレクション.add(3);
コレクション.get(0); // => 15

大きな利点は、この方法で宣言されたメソッドは関数として名前が付けられ、デバッグに便利であることです。 上記の例から collection.add.name を実行すると、関数名「add」が返されます。

3. スーパーの使用

JS の興味深い改善点は、プロトタイプ チェーンから継承されたプロパティにアクセスする方法として super キーワードを使用できることです。 次の例を見てください。

var calc = {
  数値: null、
  要素の合計(){
    this.numbers.reduce(function(a, b) { を返す
      a + b を返します。
    });
  },
};
var 数字 = {
  __proto__: calc、
  数字: [4, 6, 7],
  要素の合計(){
    this.numbers == null || this.numbers.length === 0 の場合 {
      0を返します。
    }
    super.sumElements() を返します。
  },
};
numbers.sumElements(); // => 17

calc は、numbers オブジェクトのプロトタイプです。 数値の sumElements メソッドでは、 super キーワードを使用してプロトタイプからメソッドにアクセスできます: super.sumElements()

結局のところ、super はオブジェクトのプロトタイプ チェーンから継承されたプロパティにアクセスするためのショートカットです。

前の例では、calc.sumElements() を直接実行してプロトタイプを呼び出そうとすると、エラーが発生します。 ただし、super.sumElements() はオブジェクトのプロトタイプ チェーンにアクセスするため、正しく呼び出すことができます。また、プロトタイプの sumElements() メソッドが this.numbers を使用して配列に正しくアクセスしていることを確認します。

super が存在すると、継承されたプロパティが使用されることが明確になります。

3.1 スーパーの使用制限

super は、オブジェクトリテラル内の短縮メソッド定義内でのみ使用できます。

通常のメソッド宣言 { name: function(){} } からアクセスしようとすると、JS はエラーをスローします。

var calc = {
  数値: null、
  要素の合計(){
    this.numbers.reduce(function(a, b) { を返す
      a + b を返します。
    });
  },
};
var 数字 = {
  __proto__: calc、
  数字: [4, 6, 7],
  要素の合計: 関数() {
    this.numbers == null || this.numbers.length === 0 の場合 {
      0を返します。
    }
    super.sumElements() を返します。
  },
};
// SyntaxError がスローされます: 'super' キーワードは予期されていません
数値.sumElements();

メソッド sumElements は、プロパティとして定義されます: sumElements: function() {…}。 super は短縮メソッド内でのみ使用できるため、このコンテキストで呼び出すと、SyntaxError: 'super' keyword expected here がスローされます。

この制限は、オブジェクトリテラルの宣言方法に大きな影響を与えません。 通常は、構文が短いため、短縮メソッド定義を使用する方が適切です。

4. 計算されたプロパティ名

ES6 より前では、オブジェクトはリテラル値 (通常は静的文字列) を使用して初期化されていました。 計算された名前を持つプロパティを作成するには、プロパティ アクセサーを使用する必要があります。

関数プレフィックス(prefStr, 名前) {
  prefStr + '_' + 名前を返します。
}
var オブジェクト = {};
オブジェクト[プレフィックス('number', 'pi')] = 3.14;
オブジェクト[プレフィックス('bool', 'false')] = false;
オブジェクト; // => { number_pi: 3.14, bool_false: false }

もちろん、プロパティを定義するこの方法は満足のいくものです。

次に、ショートカット メソッドを使用して上記の例を変更します。

関数プレフィックス(prefStr, 名前) {
  prefStr + '_' + 名前を返します。
}
varオブジェクト = {
  [接頭辞('数値', '円周率')]: 3.14,
  [プレフィックス('bool', 'false')]: 偽、
};
オブジェクト; // => { number_pi: 3.14, bool_false: false }

[prefix('number', 'pi')] は、prefix('number', 'pi') 式 (つまり 'number_pi') を評価して属性名を設定します。

同様に、[prefix('bool', 'false')] は 2 番目の属性名を 'bool_false' に設定します。

4.1 属性名としてのシンボル

シンボルは計算されたプロパティ名としても使用できます。 必ず角括弧で囲んでください: {[Symbol('name')]:'Prop value'}

たとえば、特別なプロパティ Symbol.iterator を使用して、オブジェクト自体のプロパティ名を反復処理します。 次の例に示すように:

varオブジェクト = {
   番号1: 14,
   番号2: 15,
   文字列1: 'こんにちは',
   文字列2: '世界',
   [シンボル.イテレータ]: 関数 *() {
     var 所有 = Object.getOwnPropertyNames(これ),
       プロップ;
     while(prop = own.pop()) {
       利回りプロップ;
     }
   }
}
[...オブジェクト]; // => ['数値1', '数値2', '文字列1', '文字列2']

[Symbol.iterator]: function *() { } オブジェクト自身のプロパティを反復処理するために使用されるプロパティを定義します。 スプレッド演算子 [...] オブジェクトはイテレータを受け取り、独自のプロパティのリストを返します。

5. 残りと拡張プロパティ

残存プロパティを使用すると、オブジェクトが割り当てられて破棄された後に残っているプロパティをオブジェクトから収集できます。

次の例では、オブジェクトを分解した後、残りのプロパティを収集します。

varオブジェクト = {
  プロップA: 1,
  プロップB: 2,
  プロップC: 3,
};
propA、...restObject をオブジェクトとします。
propA; // => 1
restObject; // => { propB: 2, propC: 3 }

スプレッド プロパティを使用すると、ソース オブジェクトの独自のプロパティをオブジェクト リテラルにコピーできます。 この例では、オブジェクト リテラルはソース オブジェクトからオブジェクトに追加のプロパティを収集します。

var ソース = {
  プロップB: 2,
  プロップC: 3,
};
varオブジェクト = {
  プロップA: 1,
  ...ソース、
};
オブジェクト; // => { propA: 1, propB: 2, propC: 3 }

6. まとめ

オブジェクトリテラルという比較的小さな構造でさえ、ES6 では大幅に改善されています。

オブジェクトのプロトタイプは、__proto__ プロパティ名を使用して初期化子から直接設定できます。 これは Object.create() を使用するよりも簡単です。

__proto__ は ES6 標準の Annex B の一部であり、その使用は推奨されないことに注意してください。 このアドオンの実装はブラウザでは必須ですが、他の環境ではオプションです。この機能は、NodeJS 4、5、6 でサポートされています。

メソッド宣言フォームが短くなったため、関数キーワードを入力する必要がなくなりました。 簡略化された方法では、 super キーワードを使用できます。これにより、オブジェクトのプロトタイプ チェーン内の継承されたプロパティに簡単にアクセスできます。

プロパティ名が実行時に計算される場合は、計算されたプロパティ名 [式] を使用してオブジェクトを初期化できるようになりました。

以上がJSにおけるオブジェクトリテラルの詳しい説明です。JSオブジェクトリテラルの詳細については、123WORDPRESS.COMの他の関連記事もご覧ください。

以下もご興味があるかもしれません:
  • JavaScript オブジェクトリテラルとコンストラクタの原理と使用法の詳細な説明
  • jsリテラル、オブジェクトリテラルアクセス、キーワードの使用に関する簡単な説明
  • Javascript オブジェクトリテラルの理解
  • JavaScript オブジェクトリテラルの説明
  • JavaScript 面接でよくテストされる文字列操作の完全なリスト (ES6 を含む)
  • JavaScript ES6クラスの実装原理の詳細な説明
  • ノードターミナルでjsファイルを実行するとES6構文がサポートされないという問題を解決します
  • JS オブジェクト指向プログラミング - ES6 におけるクラス継承の詳細な説明
  • ネイティブ JavaScript es6 でのクラス使用の分析

<<:  Linux クラウド サーバーに新しいディスクをマウントする方法

>>:  MySQL の日付関数と日付変換およびフォーマット関数

推薦する

CSS3 引用のソースと出典をマークする方法

疫病のせいで家にこもりきりで、頭がおかしくなりそうなので、パソコンを起動して頭を働かせてみました。今...

Ubuntu Linuxシステムをインストールするときにハードディスクをパーティション分割する最も合理的な方法の詳細な説明

Windows または Linux オペレーティング システムをインストールするかどうかに関係なく、...

CSS3 でクールなスライス画像カルーセル効果を実現

今日は、CSS を使用してクールな画像カルーセル コンポーネントを作成する方法を学びます。その原理は...

Docker環境を構築する簡単な方法

まず、Docker とは何かを理解しましょう。 Docker は、アプリケーションをデプロイするため...

Vueはカスタムツリーコンポーネントを再帰的に実装します

この記事では、カスタムツリーコンポーネントを再帰的に実装するVueの具体的なコードを参考までに共有し...

データベース管理における 19 の MySQL 最適化方法

MySQL データベースを最適化すると、データベースの冗長性を削減できるだけでなく、データベースの実...

IE6 ウェブページ作成リファレンス IE6 デフォルトスタイル

これは実際には IE の公式ドキュメントではありません。他の人が実践を通じて開発した IE6 のデフ...

MySQLからデータをインポートする際の不正なフォーマット、インポートの遅延、データ損失などの問題を迅速に解決します。

遅い問題を完全に解決したい場合は、MySQL を MySQL 8.0 にアップグレードすることをお勧...

Vue が 4 レベルのナビゲーションと検証コードを実装する方法の例

効果: まず5つのVueインターフェースを作成する1.home.vueページ <テンプレート&...

Vue3.0はチェックボックスコンポーネントのカプセル化を実装します

この記事では、チェックボックスコンポーネントのカプセル化を実装するためのvue3.0の具体的なコード...

CSS3入力ボックスの実装コードはGoogleログインのアニメーション効果に似ています

CSS3を使用して、Googleログインページと同様の入力ボックスをアニメーション化します。効果1 ...

Vue プロジェクトで addRoutes を使用する際の問題の解決策

目次序文1. 404 ページ1. 原因2. 解決策2.白い画面を更新する1. 原因2. 解決策3. ...

GobangゲームのWebバージョンを実装するためのJavaScript

この記事では、GobangゲームのWebバージョンを実装するためのJavaScriptの具体的なコー...

div の水平レイアウトを両側に揃える 3 つの方法

この記事では、主に、div の水平レイアウトの両側の配置を実装する 3 つの方法を紹介し、それらを共...

スケジュールされた時間に古いジャンクファイルを自動的に削除する Linux 用の Autotrash ツール

Autotrash は、古い削除済みファイルを消去するプロセスを自動化するコマンド ライン プログラ...