目次
シンボルとは
シンボルをオブジェクト属性として使用する
プロパティ名の競合の防止
ホームページ ウェブフロントエンド jsチュートリアル JavaScript での Symbol 型の用途は何ですか?

JavaScript での Symbol 型の用途は何ですか?

Mar 19, 2019 am 11:19 AM
es6 javascript フロントエンド プログラマー

この記事では、JavaScript での Symbol 型の用途について説明します。一定の参考値があるので、困っている友人は参考にしていただければ幸いです。

Symbols は ES6 で導入された新しいデータ型で、特にオブジェクト プロパティに関して JS にいくつかの利点をもたらします。しかし、文字列にはできず、文字列には何ができるのでしょうか?

シンボルについて説明する前に、多くの開発者が気づいていない可能性がある JavaScript の機能をいくつか見てみましょう。

背景

jsのデータ型は大きく分けて値型と参照型の2種類に分かれます。

値型(基本型):数値型(数値型) )、文字型 (String)、ブール型 (Boolean)、null およびアンダーファイン参照型 (クラス): 関数、オブジェクト、配列など。

値の型の理解: 変数間の相互代入、冒頭を参照新しいメモリ空間を作成し、変数値を新しい変数に割り当て、新しく開かれたメモリに保存します。その後の 2 つの変数の値の変更は相互に影響しません。たとえば:

var a=10; //开辟一块内存空间保存变量a的值“10”;
var b=a; //给变量 b 开辟一块新的内存空间,将 a 的值 “10” 赋值一份保存到新的内存里;
//a 和 b 的值以后无论如何变化,都不会影响到对方的值;
ログイン後にコピー

C などの一部の言語には、参照渡しと値渡しの概念があります。 JavaScript にも同様の概念があり、渡されたデータのタイプに基づいて推論されます。値が関数に渡された場合、値を再割り当てしても呼び出し場所の値は変更されません。ただし、参照型を変更すると、変更された値も呼び出された場所で変更されます。

参照型の理解: 変数間の相互代入は、オブジェクト (通常のオブジェクト、関数オブジェクト、配列オブジェクト) を新しい変数にコピーするのではなく、単なるポインターの交換です。まだオブジェクトは 1 つだけですが、ガイドがもう 1 つだけあります~~; 例:

var a={x:1,y:2} //需要开辟内存空间保存对象,变量 a 的值是一个地址,这个地址指向保存对象的空间;
var b=a; // 将a 的指引地址赋值给 b,而并非复制一给对象且新开一块内存空间来保存;
// 这个时候通过 a 来修改对象的属性,则通过 b 来查看属性时对象属性已经发生改变;
ログイン後にコピー

ある値型 (謎の NaN 値を除く) は、同じ値を持つ別の値型と常に正確に等しくなります。次のようになります:

const first = "abc" + "def";
const second = "ab" + "cd" + "ef";
console.log(first === second); // true
ログイン後にコピー

ただし、同じ構造を持つ参照型は等しくありません:

const obj1 = { name: "Intrinsic" };
const obj2 = { name: "Intrinsic" };
console.log(obj1 === obj2); // false
// 但是,它们的 .name 属性是基本类型:
console.log(obj1.name === obj2.name); // true
ログイン後にコピー

オブジェクトは JavaScript 言語で重要な役割を果たしており、あらゆる場所で使用されます。オブジェクトはキーと値のペアのコレクションとしてよく使用されますが、この方法でオブジェクトを使用するには大きな制限があります。symbol が登場する前は、オブジェクトのキーは文字列のみであり、非文字を使用する 文字列値がオブジェクトのキーとして使用される場合、値は次のように強制的に文字列に変換されます。

const obj = {};
obj.foo = 'foo';
obj['bar'] = 'bar';
obj[2] = 2;
obj[{}] = 'someobj';
console.log(obj);
// { '2': 2, foo: 'foo', bar: 'bar',
     '[object Object]': 'someobj' }
ログイン後にコピー

シンボルとは

シンボル() この関数はシンボル タイプを返します。このタイプの値には静的プロパティと静的メソッドがあります。その静的プロパティはいくつかの組み込みメンバー オブジェクトを公開します。その静的メソッドはグローバル シンボル登録を公開し、組み込みオブジェクト クラスに似ていますが、構文 "new Symbol( )「。したがって、Symbol を使用して生成された値は等しくありません。

const s1 = Symbol();
const s2 = Symbol();
console.log(s1 === s2); // false
ログイン後にコピー

symbol をインスタンス化するとき、オプションで文字列を指定できるオプションの最初のパラメータがあります。この値はコードのデバッグに使用することを目的としています。それ以外の場合は、symbol 自体には実際には影響しません。

const s1 = Symbol('debug');
const str = 'debug';
const s2 = Symbol('xxyy');
console.log(s1 === str); // false
console.log(s1 === s2); // false
console.log(s1); // Symbol(debug)
ログイン後にコピー

シンボルをオブジェクト属性として使用する

シンボルにはもう 1 つの重要な用途があり、次のようにオブジェクトのキーとして使用できます。

const obj = {};
const sym = Symbol();
obj[sym] = 'foo';
obj.bar = 'bar';
console.log(obj); // { bar: 'bar' }
console.log(sym in obj); // true
console.log(obj[sym]); // foo
console.log(Object.keys(obj)); // ['bar']
ログイン後にコピー

一見すると、これは次のように見えます。 symbol を使用してオブジェクトにプライベート プロパティを作成できるのと同様、他の多くのプログラミング言語でもクラス内に独自のプライベート プロパティがあり、プライベート プロパティの省略は常に JavaScript の欠点と考えられてきました。

残念ながら、オブジェクトと対話するコードは、キーがシンボルであるオブジェクトのプロパティに引き続きアクセスできます。これは、呼び出しコードがまだシンボル自体にアクセスできない場合でも可能です。たとえば、Reflect.ownKeys() メソッドは、文字列や記号を含む、オブジェクト上のすべてのキーのリストを取得できます。

function tryToAddPrivate(o) {
  o[Symbol('Pseudo Private')] = 42;
}
const obj = { prop: 'hello' };
tryToAddPrivate(obj);
console.log(Reflect.ownKeys(obj));
// [ 'prop', Symbol(Pseudo Private) ]
console.log(obj[Reflect.ownKeys(obj)[1]]); // 42
ログイン後にコピー
注: 現在、次のような処理を行うための作業が行われています。 JavaScript でのクラスへのクラスの追加 プライベート プロパティの追加に関する問題。この機能の名前はプライベート フィールドと呼ばれます。これはすべてのオブジェクトにメリットがあるわけではありませんが、クラスのインスタンスであるオブジェクトにはメリットがあります。プライベート フィールドは Chrome 74 以降で利用可能です。

プロパティ名の競合の防止

シンボルは、オブジェクトにプライベート プロパティを提供する JavaScript の恩恵を直接受けられない可能性があります。ただし、それらは別の理由で有益です。これらは、異なるライブラリが名前の競合の危険を冒さずにオブジェクトにプロパティを追加したい場合に役立ちます。

Symbol JavaScript オブジェクトにプライベート プロパティを提供するのは少し難しいですが、Symbol には別の利点があります。それは、異なるライブラリがオブジェクトにプロパティを追加するときに名前が競合するリスクを回避できることです。

2 つの異なるライブラリがオブジェクトに基本データを追加したい状況を考えてみましょう。おそらく、両方ともオブジェクトに何らかの識別子を設定したいと考えているでしょう。単純に id をキーとして使用すると、複数のライブラリが同じキーを使用する大きな危険があります。

function lib1tag(obj) {
  obj.id = 42;
}
function lib2tag(obj) {
  obj.id = 369;
}
ログイン後にコピー

シンボルを使用すると、各ライブラリはインスタンス化時に必要なシンボルを生成できます。次に、生成された Symbol の値をオブジェクトのプロパティとして使用します。

const library1property = Symbol('lib1');
function lib1tag(obj) {
  obj[library1property] = 42;
}
const library2property = Symbol('lib2');
function lib2tag(obj) {
  obj[library2property] = 369;
}
ログイン後にコピー

このため、Symbol は JavaScript にとって有益であると思われます。

しかし、なぜ各ライブラリは単にランダムな文字列を生成したり、インスタンス化時に名前空間を使用したりできないのかと疑問に思われるかもしれません。

const library1property = uuid(); // random approach
function lib1tag(obj) {
  obj[library1property] = 42;
}
const library2property = 'LIB2-NAMESPACE-id'; // namespaced approach
function lib2tag(obj) {
  obj[library2property] = 369;
}
ログイン後にコピー

这种方法是没错的,这种方法实际上与 Symbol 的方法非常相似,除非两个库选择使用相同的属性名,否则不会有冲突的风险。

在这一点上,聪明的读者会指出,这两种方法并不完全相同。我们使用唯一名称的属性名仍然有一个缺点:它们的键非常容易找到,特别是当运行代码来迭代键或序列化对象时。考虑下面的例子:

const library2property = 'LIB2-NAMESPACE-id'; // namespaced
function lib2tag(obj) {
  obj[library2property] = 369;
}
const user = {
  name: 'Thomas Hunter II',
  age: 32
};
lib2tag(user);
JSON.stringify(user);
// '{"name":"Thomas Hunter II","age":32,"LIB2-NAMESPACE-id":369}'
ログイン後にコピー

如果我们为对象的属性名使用了 Symbol,那么 JSON 输出将不包含它的值。这是为什么呢? 虽然 JavaScript 获得了对 Symbol 的支持,但这并不意味着 JSON 规范已经改变! JSON 只允许字符串作为键,JavaScript 不会尝试在最终 JSON 有效负载中表示 Symbol 属性。

const library2property = 'f468c902-26ed-4b2e-81d6-5775ae7eec5d'; // namespaced approach
function lib2tag(obj) {
  Object.defineProperty(obj, library2property, {
    enumerable: false,
    value: 369
  });
}
const user = {
  name: 'Thomas Hunter II',
  age: 32
};
lib2tag(user);
console.log(user); // {name: "Thomas Hunter II", age: 32, f468c902-26ed-4b2e-81d6-5775ae7eec5d: 369}
console.log(JSON.stringify(user)); // {"name":"Thomas Hunter II","age":32}
console.log(user[library2property]); // 369
ログイン後にコピー

通过将 enumerable 属性设置为 false 而“隐藏”的字符串键的行为非常类似于 Symbol 键。它们通过 Object.keys() 遍历也看不到,但可以通过 Reflect.ownKeys() 显示,如下的示例所示:

const obj = {};
obj[Symbol()] = 1;
Object.defineProperty(obj, 'foo', {
  enumberable: false,
  value: 2
});
console.log(Object.keys(obj)); // []
console.log(Reflect.ownKeys(obj)); // [ 'foo', Symbol() ]
console.log(JSON.stringify(obj)); // {}
ログイン後にコピー

在这点上,我们几乎重新创建了 Symbol。隐藏的字符串属性和 Symbol 都对序列化器隐藏。这两个属性都可以使用Reflect.ownKeys()方法读取,因此它们实际上不是私有的。假设我们为属性名的字符串版本使用某种名称空间/随机值,那么我们就消除了多个库意外发生名称冲突的风险。

但是,仍然有一个微小的区别。由于字符串是不可变的,而且 Symbol 总是保证惟一的,所以仍然有可能生成字符串组合会产生冲突。从数学上讲,这意味着 Symbol 确实提供了我们无法从字符串中得到的好处。

在 Node.js 中,检查对象时(例如使用 console.log() ),如果遇到名为 inspect 的对象上的方法,将调用该函数,并将打印内容。可以想象,这种行为并不是每个人都期望的,通常命名为 inspect 的方法经常与用户创建的对象发生冲突。

现在 Symbol 可用来实现这个功能,并且可以在 equire('util').inspect.custom 中使用。inspect 方法在Node.js v10 中被废弃,在 v1 1中完全被忽略, 现在没有人会偶然改变检查的行为。

模拟私有属性

这里有一个有趣的方法,我们可以用来模拟对象上的私有属性。这种方法将利用另一个 JavaScript 特性: proxy(代理)。代理本质上封装了一个对象,并允许我们对与该对象的各种操作进行干预。

代理提供了许多方法来拦截在对象上执行的操作。我们可以使用代理来说明我们的对象上可用的属性,在这种情况下,我们将制作一个隐藏我们两个已知隐藏属性的代理,一个是字符串 _favColor,另一个是分配给 favBook 的 S ymbol :

let proxy;

{
  const favBook = Symbol('fav book');

  const obj = {
    name: 'Thomas Hunter II',
    age: 32,
    _favColor: 'blue',
    [favBook]: 'Metro 2033',
    [Symbol('visible')]: 'foo'
  };

  const handler = {
    ownKeys: (target) => {
      const reportedKeys = [];
      const actualKeys = Reflect.ownKeys(target);

      for (const key of actualKeys) {
        if (key === favBook || key === '_favColor') {
          continue;
        }
        reportedKeys.push(key);
      }

      return reportedKeys;
    }
  };

  proxy = new Proxy(obj, handler);
}

console.log(Object.keys(proxy)); // [ 'name', 'age' ]
console.log(Reflect.ownKeys(proxy)); // [ 'name', 'age', Symbol(visible) ]
console.log(Object.getOwnPropertyNames(proxy)); // [ 'name', 'age' ]
console.log(Object.getOwnPropertySymbols(proxy)); // [Symbol(visible)]
console.log(proxy._favColor); // 'blue'
ログイン後にコピー

使用 _favColor 字符串很简单:只需阅读库的源代码即可。 另外,通过蛮力找到动态键(例如前面的 uuid 示例)。但是,如果没有对 Symbol 的直接引用,任何人都不能 从proxy  对象访问'Metro 2033'值。

Node.js警告:Node.js中有一个功能会破坏代理的隐私。 JavaScript语 言本身不存在此功能,并且不适用于其他情况,例 如Web 浏览器。 它允许在给定代理时获得对底层对象的访问权。 以下是使用此功能打破上述私有属性示例的示例:

const [originalObject] = process
  .binding('util')
  .getProxyDetails(proxy);
const allKeys = Reflect.ownKeys(originalObject);
console.log(allKeys[3]); // Symbol(fav book)
ログイン後にコピー

现在,我们需要修改全局 Reflect 对象,或者修改 util 流程绑定,以防止它们在特定的 Node.js 实例中使用。但这是一个可怕的兔子洞。

本篇文章到这里就已经全部结束了,更多其他精彩内容可以关注PHP中文网的JavaScript教程视频栏目!

以上がJavaScript での Symbol 型の用途は何ですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

どのAIプログラマーが一番優れているでしょうか? Devin、Tongyi Lingma、SWE エージェントの可能性を探る どのAIプログラマーが一番優れているでしょうか? Devin、Tongyi Lingma、SWE エージェントの可能性を探る Apr 07, 2024 am 09:10 AM

世界初の AI プログラマー Devin の誕生から 1 か月も経たない 2022 年 3 月 3 日、プリンストン大学の NLP チームはオープンソース AI プログラマー SWE-agent を開発しました。 GPT-4 モデルを利用して、GitHub リポジトリの問題を自動的に解決します。 SWE ベンチ テスト セットにおける SWE エージェントのパフォーマンスは Devin と同様で、平均 93 秒かかり、問題の 12.29% を解決しました。専用端末と対話することで、SWE エージェントはファイルの内容を開いて検索したり、自動構文チェックを使用したり、特定の行を編集したり、テストを作成して実行したりできます。 (注: 上記の内容は元の内容を若干調整したものですが、原文の重要な情報は保持されており、指定された文字数制限を超えていません。) SWE-A

PHP と Vue: フロントエンド開発ツールの完璧な組み合わせ PHP と Vue: フロントエンド開発ツールの完璧な組み合わせ Mar 16, 2024 pm 12:09 PM

PHP と Vue: フロントエンド開発ツールの完璧な組み合わせ 今日のインターネットの急速な発展の時代において、フロントエンド開発はますます重要になっています。 Web サイトやアプリケーションのエクスペリエンスに対するユーザーの要求がますます高まっているため、フロントエンド開発者は、より効率的で柔軟なツールを使用して、応答性の高いインタラクティブなインターフェイスを作成する必要があります。フロントエンド開発の分野における 2 つの重要なテクノロジーである PHP と Vue.js は、組み合わせることで完璧なツールと見なされます。この記事では、PHP と Vue の組み合わせと、読者がこれら 2 つをよりよく理解し、適用できるようにするための詳細なコード例について説明します。

C言語の魅力に迫る ~プログラマーの可能性を引き出す~ C言語の魅力に迫る ~プログラマーの可能性を引き出す~ Feb 24, 2024 pm 11:21 PM

C言語学習の魅力:プログラマーの可能性を引き出す テクノロジーの発展に伴い、コンピュータプログラミングは大きな注目を集めている分野です。数あるプログラミング言語の中でもC言語は常にプログラマーに愛されています。そのシンプルさ、効率性、幅広い用途により、C 言語の学習は、多くの人にとってプログラミングの分野に入る最初のステップとなっています。この記事では、C言語を学ぶ魅力と、C言語を学ぶことでプログラマーの可能性を引き出す方法について解説します。 C言語学習の魅力は、まずその簡単さにあります。他のプログラミング言語と比較すると、C言語は

フロントエンドの面接官からよく聞かれる質問 フロントエンドの面接官からよく聞かれる質問 Mar 19, 2024 pm 02:24 PM

フロントエンド開発のインタビューでは、HTML/CSS の基本、JavaScript の基本、フレームワークとライブラリ、プロジェクトの経験、アルゴリズムとデータ構造、パフォーマンスの最適化、クロスドメイン リクエスト、フロントエンド エンジニアリング、デザインパターン、新しいテクノロジーとトレンド。面接官の質問は、候補者の技術スキル、プロジェクトの経験、業界のトレンドの理解を評価するように設計されています。したがって、候補者はこれらの分野で自分の能力と専門知識を証明するために十分な準備をしておく必要があります。

簡単な JavaScript チュートリアル: HTTP ステータス コードを取得する方法 簡単な JavaScript チュートリアル: HTTP ステータス コードを取得する方法 Jan 05, 2024 pm 06:08 PM

JavaScript チュートリアル: HTTP ステータス コードを取得する方法、特定のコード例が必要です 序文: Web 開発では、サーバーとのデータ対話が頻繁に発生します。サーバーと通信するとき、多くの場合、返された HTTP ステータス コードを取得して操作が成功したかどうかを判断し、さまざまなステータス コードに基づいて対応する処理を実行する必要があります。この記事では、JavaScript を使用して HTTP ステータス コードを取得する方法を説明し、いくつかの実用的なコード例を示します。 XMLHttpRequestの使用

Django はフロントエンドですか、バックエンドですか?それをチェックしてください! Django はフロントエンドですか、バックエンドですか?それをチェックしてください! Jan 19, 2024 am 08:37 AM

Django は、迅速な開発とクリーンなメソッドを重視した Python で書かれた Web アプリケーション フレームワークです。 Django は Web フレームワークですが、Django がフロントエンドなのかバックエンドなのかという質問に答えるには、フロントエンドとバックエンドの概念を深く理解する必要があります。フロントエンドはユーザーが直接対話するインターフェイスを指し、バックエンドはサーバー側プログラムを指し、HTTP プロトコルを通じてデータと対話します。フロントエンドとバックエンドが分離されている場合、フロントエンドとバックエンドのプログラムをそれぞれ独立して開発して、ビジネス ロジックとインタラクティブ効果、およびデータ交換を実装できます。

Go 言語のフロントエンド テクノロジーの探求: フロントエンド開発の新しいビジョン Go 言語のフロントエンド テクノロジーの探求: フロントエンド開発の新しいビジョン Mar 28, 2024 pm 01:06 PM

Go 言語は、高速で効率的なプログラミング言語として、バックエンド開発の分野で広く普及しています。ただし、Go 言語をフロントエンド開発と結びつける人はほとんどいません。実際、フロントエンド開発に Go 言語を使用すると、効率が向上するだけでなく、開発者に新たな視野をもたらすことができます。この記事では、フロントエンド開発に Go 言語を使用する可能性を探り、読者がこの分野をよりよく理解できるように具体的なコード例を示します。従来のフロントエンド開発では、ユーザー インターフェイスの構築に JavaScript、HTML、CSS がよく使用されます。

Django: フロントエンド開発とバックエンド開発の両方を処理できる魔法のフレームワークです。 Django: フロントエンド開発とバックエンド開発の両方を処理できる魔法のフレームワークです。 Jan 19, 2024 am 08:52 AM

Django: フロントエンド開発とバックエンド開発の両方を処理できる魔法のフレームワークです。 Django は、効率的でスケーラブルな Web アプリケーション フレームワークです。 MVCやMTVなど複数のWeb開発モデルをサポートし、高品質なWebアプリケーションを簡単に開発できます。 Django はバックエンド開発をサポートするだけでなく、フロントエンド インターフェイスを迅速に構築し、テンプレート言語を通じて柔軟なビュー表示を実現します。 Django はフロントエンド開発とバックエンド開発をシームレスに統合するため、開発者は学習に特化する必要がありません。

See all articles