JavaScript プリミティブデータ型シンボルの詳細な説明

JavaScript プリミティブデータ型シンボルの詳細な説明

導入

シンボル変数を作成する最も簡単な方法は、Symbol() 関数を使用することです。 sysmbol 変数には 2 つの特別な機能があります。

1. オブジェクト属性名として使用できます。オブジェクト属性名として使用できるのは、文字列型とシンボル型のみです。

2. 2 つのシンボルが同じ値を持つことはありません。

const シンボル1 = シンボル();
const シンボル2 = シンボル();

シンボル1 === シンボル2; // 偽

定数obj = {};
obj[symbol1] = 'こんにちは';
obj[symbol2] = 'ワールド';

obj[シンボル1]; // 'こんにちは'
obj[symbol2]; // 'ワールド'

Symbol() を呼び出すとオブジェクトのように見えますが、シンボルは実際には JavaScript のプリミティブ データ型です。 Symbol をコンストラクターとして new を使用すると、エラーが発生します。

const シンボル1 = シンボル();

typeof symbol1; // 'シンボル'
symbol1 instanceof Object; // false

// "TypeError: シンボルはコンストラクタではありません" をスローします
新しいシンボル();

説明

Symbol() 関数は、文字列の説明という 1 つのパラメータのみを取ります。この文字列パラメータの唯一の用途は、デバッグを支援すること、つまりその toString() 値です。ただし、同じ説明を持つ 2 つのシンボルは等しくないことに注意してください。

const symbol1 = Symbol('私のシンボル');
const symbol2 = Symbol('私のシンボル');

シンボル1 === シンボル2; // 偽
console.log(symbol1); // 'Symbol(私のシンボル)'

グローバル シンボル レジストリがあり、Symbol.for() で作成されたシンボルはこのレジストリに追加され、その説明を使用してインデックスが付けられます。つまり、Symbol.for() を使用して同じ説明を持つ 2 つのシンボルを作成した場合、それらは等しくなります。

const symbol1 = Symbol.for('test');
const symbol2 = Symbol.for('test');

シンボル1 === シンボル2; // 真
console.log(symbol1); // 'シンボル(テスト)'

一般的に、名前の競合が発生する可能性があるため、特別な理由がない限り、グローバル レジストリを使用しないでください。

名前の競合

JavaScript には組み込みシンボルがあり、ES6 では Symbol.iterator です。 Symbol.iterator 関数を持つオブジェクトは反復可能オブジェクトと呼ばれ、オブジェクトに対して for/of ループを使用できることを意味します。

定数フィボナッチ = {
  [シンボル.イテレータ]: 関数*() {
    a = 1 とします。
    b = 1 とします。
    温度を調節する

    b を生成します。

    (真)の間{
      温度 = ;
      a = a + b;
      b = 温度;
      b を生成します。
    }
  }
};

// 100 未満のすべてのフィボナッチ数を出力します
(フィボナッチの定数x) {
  (x >= 100)の場合{
    壊す;
  }
  コンソールログ(x);
}

ここで文字列ではなく Symbol.iterator を使用するのはなぜですか? Symbol.iterator が使用されていないと仮定すると、反復可能なオブジェクトには、次の反復可能なオブジェクト クラスのように、'iterator' という名前の文字列属性が必要です。

クラス MyClass {
  コンストラクタ(obj) {
    オブジェクトに代入します。
  }

  イテレータ() {
    const keys = Object.keys(this);
    i = 0 とします。
    戻り値 (関数*() {
      i >= キーの長さの場合{
        戻る;
      }
      keys[i++]を生成します。
    })();
  }
}

MyClass のインスタンスは反復可能なオブジェクトであり、オブジェクトのプロパティを走査できます。しかし、上記のクラスには潜在的な欠陥があります。悪意のあるユーザーが、反復子プロパティを持つオブジェクトを MyClass コンストラクターに渡すとします。

const obj = new MyClass({ iterator: '関数ではありません' });

このように、obj に対して for/of を使用すると、JavaScript は TypeError: obj is not iterable 例外をスローします。オブジェクトに渡されたイテレータ関数がクラスのイテレータ プロパティをオーバーライドしていることがわかります。これは、プロトタイプ汚染のセキュリティ問題に多少似ています。ユーザーデータを無意識にコピーすると、__proto__ やコンストラクターなどの一部の特殊なプロパティに問題が発生します。

ここで重要な点は、シンボルがオブジェクトの内部データとユーザー データを分離して保持することです。 sysmbol は JSON で表現できないため、不適切な Symbol.iterator プロパティを持つデータを Express API に渡すことについて心配する必要はありません。さらに、Mongoose モデルなど、組み込み関数とユーザー データを混在させるオブジェクトの場合、シンボルを使用して、ユーザー データが組み込み属性と競合しないようにすることができます。

私有財産

2 つのシンボルは等しくないため、JavaScript でプライベート プロパティをシミュレートするために簡単に使用できます。シンボルは Object.keys() の結果には表示されないため、シンボルを明示的にエクスポートするか、Object.getOwnPropertySymbols() を使用して取得しない限り、他のコードはこのプロパティにアクセスできません。

関数 getObj() {
  const シンボル = シンボル('テスト');
  定数obj = {};
  obj[シンボル] = 'テスト';
  obj を返します。
}

定数obj = getObj();

オブジェクト.keys(obj); // []

// このシンボルへの参照がない限り、このプロパティにアクセスすることはできません obj[Symbol('test')]; // undefined

// getOwnPropertySymbols() を使用して、シンボルへの参照を取得します。const [symbol] = Object.getOwnPropertySymbols(obj);
obj[シンボル]; // 'テスト'

もう 1 つの理由は、シンボルが JSON.stringify() の結果に表示されないことです。より正確に言うと、JSON.stringify() はシンボルの属性名と属性値を無視します。

const シンボル = シンボル('テスト');
const obj = { [シンボル]: 'テスト', テスト: シンボル };

JSON.stringify(obj); // "{}"

要約する

オブジェクトの内部状態を表すためにシンボルを使用すると、ユーザー データとプログラムの状態を効果的に分離できます。これにより、内部プロパティを「$」で始めるなどの特定の命名規則は必要なくなります。次回プライベート プロパティを定義する必要がある場合は、Symbol 型を試してください。

上記は、JavaScript プリミティブ データ型 Symbol の詳細な説明です。JavaScript プリミティブ データ型 Symbol の詳細については、123WORDPRESS.COM の他の関連記事に注目してください。

以下もご興味があるかもしれません:
  • JavaScript のプリミティブデータ型 Null と Undefined の詳細な説明
  • JavaScript の 2 つの新しいプリミティブ データ型 (レコードとタプル) の詳細な説明

<<:  mysql8.0.0 winx64.zip 解凍バージョンのインストールと設定のチュートリアル

>>:  Linux でローカル コンピューターとリモート サーバーのポートが接続されているかどうかを確認する方法

推薦する

Docker コンテナを他のサーバーに移行する 5 つの方法

多くの場合、移行は避けられません。ハードウェアのアップグレード、データ センターの変更、古いオペレー...

vue-cropper コンポーネントは画像の切り取りとアップロードを実現します

この記事では、画像の切り取りとアップロードを実装するためのvue-cropperコンポーネントの具体...

JS を使って 1 分で github+Jekyll ブログに訪問カウント機能を追加する実装

目次1分でgithub+Jekyllブログにトラフィック機能を追加する1. ジェクルとは何か1. J...

Vue で親コンポーネントから子コンポーネントにデータを渡すいくつかの方法

最近、Vue のソースコードを勉強していて、Vue で親コンポーネントと子コンポーネント間でデータを...

使用場所によって混乱しやすいXHTMLタグ

<br />jb51.net では、常に記事のセマンティクスを重視してきましたが、HTM...

Windows 10 での MySQL 8.0.12 解凍バージョンのインストール グラフィック チュートリアル

この記事は、MySQL 8.0.12解凍版のインストールグラフィックチュートリアルを記録しています。...

カルーセル効果を実現するためのネイティブJavaScript+CSS

この記事では、参考までに、カルーセル効果の具体的なコードをJavaScript+CSSを使用して実装...

Docker で Maven プロジェクトをより速くビルドする

目次I. 概要2. 従来の多段階イメージ構築3. Buildkitを使用してイメージをビルドする4....

角度付き双方向バインディングの詳細な説明

目次双方向バインディングの原理ngモデルレンダリングカスタム双方向バインディングプロパティコンポーネ...

Apache ab を使用して HTTP パフォーマンス テストを実行する

MacにはApache環境が付属していますターミナルを開き、sudo apachectl -v と入...

MySQLデータベースの数千万件のデータクエリとストレージの詳細な説明

目次百万レベルのデータ処理ソリューションデータストレージ構造設計クエリステートメントの最適化1000...

Ubuntu 20.04 IPアドレスを変更する方法の例

例:本日、前回のオフィスコラボレーションプラットフォーム実験の続きをしていたところ、仮想マシンは以前...

ウェブテーブルフレームを作成するためのヒント

<br />Web テーブル フレームを作成するためのヒント。 ------------...

MySQLクエリの文字セットの不一致の問題を解決する方法

問題を見つける最近、仕事で問題が発生しました。MySQL データベースにテーブルを作成するときに、ラ...

HTML ベースタグ target=_parent の使用の紹介

<base> タグは、ページ上のすべてのリンクのデフォルトのアドレスまたはデフォルトのタ...