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 の日付関数と日付変換およびフォーマット関数

推薦する

プレーヤー機能を実現するためのvue + element uiのサンプルコード

効果画像のない表示は単なる空虚な言葉です。 1. オーディオをベースにし、elementUI と組み...

DockerにRedisをインストールし、パスワードを設定して接続する方法

Redis は分散キャッシュ サービスです。キャッシュは、大規模システムの開発やパフォーマンスの最適...

MySQLで更新可能なビューを作成する方法の詳細な説明

この記事では、例を使用して、MySQL で更新可能なビューを作成する方法について説明します。ご参考ま...

CentOS 7 でソースコードから Openssh をインストールする方法

環境: CentOS 7.1.1503 最小インストール依存パッケージをダウンロードします: yum...

C# は MySQL コマンドラインのバックアップとリカバリを実装します

MySQL データベースをバックアップするためのツールは多数あります。過去 2 日間で、C# を使用...

VMware Workstation Pro でサーバー仮想マシンを構築する (グラフィック チュートリアル)

私が使用している VMware Workstation Pro のバージョンは次のとおりです。 1....

Centos6.5 の rpm パッケージから mysql5.7 をインストールするときに発生する初期化エラーの解決策

1. rzをサーバーにアップロードして解凍する rz [root@mini2 アップロード]# ta...

Ubuntu 20.04は静的IPアドレスを設定します(異なるバージョンを含む)

Ubuntu 20.04はnetplanを通じてネットワークを管理するため、以前のバージョンとは少...

CSSタグの表示モードの詳細な説明

ラベル表示モード(重要) divタグとspanタグ1. スタイルはまったく同じですが、ラベルが異なり...

MySql バッチに挿入するときにデータの重複を避ける方法

目次序文1. ignore を挿入2. 重複キーの更新時3. を置き換える要約する序文Mysql は...

mysql 簡単な操作例を表示

この記事では、例を挙げて mysql show 操作について説明します。ご参考までに、詳細は以下の通...

CSS3 での 2D および 3D 変換の実装

CSS3 は、要素の 2D 平面変換と視覚的な 3D 空間変換を実装します。2D 変換はより頻繁に使...

html2canvasで画像が正常にキャプチャできない時の解決方法

質問まず、私が遭遇した問題についてお話しします。まず、そういった需要があるわけです。フロントエンドは...

カルーセル効果を実現するjQueryプラグイン

毎日jQueryプラグイン - カルーセルチャートを実装するためのjQueryプラグイン。参考までに...

Windows に MySQL 8.0.16 をインストールする手順とエラーの解決方法

1. はじめに: mysql8以降は、これまでよく使われていたバージョンと比べてかなり変更点が大きい...