検索
ホームページウェブフロントエンドフロントエンドQ&Aシンボルはes6の新しいタイプですか?

symbol は es6 の新しいタイプです。 Symbol は ECMAScript6 で導入された新しい基本データ型であり、一意の値を表します; Symbol 型の値は Symbol() 関数を使用して生成する必要があります。

シンボルはes6の新しいタイプですか?

このチュートリアルの動作環境: Windows7 システム、JavaScript バージョン 1.8.5、Dell G3 コンピューター。

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

Symbol に入る前に、多くの開発者が特性に気づいていない可能性がある JavaScript の機能をいくつか見てみましょう。

Background

js のデータ型は、通常、valuetype とreferencetype ## の 2 つのタイプに分類されます。

  • #値の型(基本型): 数値型(Number)、文字型(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 来查看属性时对象属性已经发生改变;

A 値型 (謎の 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' }

シンボルとは

Symbol() この関数は、静的プロパティと静的メソッドを持つシンボル タイプの値を返します。その静的プロパティはいくつかの組み込みメンバー オブジェクトを公開します。その静的メソッドはグローバル シンボル登録を公開し、組み込みオブジェクト クラスに似ていますが、構文 "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 つの重要な用途があり、次のようにオブジェクト内のキーとして使用できます。一見すると、

symbol

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

残念ながら、オブジェクトと対話するコードは、キーがシンボルであるオブジェクトのプロパティに引き続きアクセスできます。これは、呼び出しコードがまだシンボル自体にアクセスできない場合でも可能です。たとえば、Reflect.ownKeys()

メソッドは、文字列や記号を含む、オブジェクト上のすべてのキーのリストを取得できます。

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']
注: 現在、いくつかのキーが存在します。 JavaScript でこれを処理するために作業が行われています。プライベート プロパティをクラスに追加する際の問題です。この機能の名前は

Private Fields
と呼ばれます。これはすべてのオブジェクトにメリットがあるわけではありませんが、クラスのインスタンスであるオブジェクトにはメリットがあります。プライベート フィールドは Chrome 74 以降で利用可能です。

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

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

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

考虑这样一种情况:两个不同的库想要向一个对象添加基本数据,可能它们都想在对象上设置某种标识符。通过简单地使用 id 作为键,这样存在一个巨大的风险,就是多个库将使用相同的键。

function lib1tag(obj) {
    obj.id = 42;
}
function lib2tag(obj) {
    obj.id = 369;
}

通过使用 Symbol,每个库可以在实例化时生成所需的 Symbol。然后用生成 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 实例中使用。但这是一个可怕的兔子洞。

【相关推荐:javascript视频教程web前端

以上がシンボルはes6の新しいタイプですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
es6怎么判断是否为数组es6怎么判断是否为数组Apr 25, 2022 pm 06:43 PM

在es6中,可以利用“Array.isArray()”方法判断对象是否为数组,若判断的对象是数组,返回的结果是true,若判断对象不是数组,返回的结果是false,语法为“Array.isArray(需要检测的js对象)”。

es6中遍历跟迭代的区别是什么es6中遍历跟迭代的区别是什么Apr 26, 2022 pm 02:57 PM

es6中遍历跟迭代的区别是:遍历强调的是要把整个数据依次全部取出来,是访问数据结构的所有元素;而迭代虽然也是依次取出数据,但是并不保证取多少,也不保证把所有的数据取完,是遍历的一种形式。

es6中怎么判断两个对象是否相等es6中怎么判断两个对象是否相等Apr 19, 2022 pm 03:34 PM

在es6中,可用Object对象的is()方法来判断两个对象是否相等,该方法检测两个变量的值是否为同一个值,判断两个对象的引用地址是否一致,语法“Object.is(对象1,对象2)”;该方法会返回布尔值,若返回true则表示两个对象相等。

es6怎么将数字转为字符串es6怎么将数字转为字符串Apr 19, 2022 pm 06:38 PM

转换方法:1、利用“+”给数字拼接一个空字符,语法“数字+""”;2、使用String(),可把对象的值转换为字符串,语法“String(数字对象)”;3、用toString(),可返回数字的字符串表示,语法“数字.toString()”。

es6中assign的用法是什么es6中assign的用法是什么May 05, 2022 pm 02:25 PM

在es6中,assign用于对象的合并,可以将源对象的所有可枚举属性复制到目标对象;若目标对象与源对象有同名属性,或多个源对象有同名属性,则后面的属性会覆盖前面的属性,语法为“Object.assign(...)”

es6怎么改变数组数据es6怎么改变数组数据Apr 26, 2022 am 10:08 AM

改变方法:1、利用splice()方法修改,该方法可以直接修改原数组的内容,语法为“数组.splice(开始位置,修改个数,修改后的值)”;2、利用下标访问数组元素,并重新赋值来修改数组数据,语法为“数组[下标值]=修改后的值;”。

sort排序是es6中的吗sort排序是es6中的吗Apr 25, 2022 pm 03:30 PM

sort排序是es6中的;sort排序是es6中用于对数组的元素进行排序的方法,该方法默认不传参,按照字符编码顺序进行排序,排序顺序可以是字母或数字,并按升序或降序,语法为“array.sort(callback(a,b))”。

import as在es6中的用法是什么import as在es6中的用法是什么Apr 25, 2022 pm 05:19 PM

在es6中,import as用于将若干export导出的内容组合成一个对象返回;ES6的模块化分为导出与导入两个模块,该方法能够将所有的导出内容包裹到指定对象中,语法为“import * as 对象 from ...”。

See all articles

ホット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ヘンタイを無料で生成します。

ホットツール

Dreamweaver Mac版

Dreamweaver Mac版

ビジュアル Web 開発ツール

Safe Exam Browser

Safe Exam Browser

Safe Exam Browser は、オンライン試験を安全に受験するための安全なブラウザ環境です。このソフトウェアは、あらゆるコンピュータを安全なワークステーションに変えます。あらゆるユーティリティへのアクセスを制御し、学生が無許可のリソースを使用するのを防ぎます。

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

SAP NetWeaver Server Adapter for Eclipse

SAP NetWeaver Server Adapter for Eclipse

Eclipse を SAP NetWeaver アプリケーション サーバーと統合します。

SublimeText3 英語版

SublimeText3 英語版

推奨: Win バージョン、コードプロンプトをサポート!