Rumah  >  Artikel  >  hujung hadapan web  >  Adakah simbol jenis baru dalam es6?

Adakah simbol jenis baru dalam es6?

青灯夜游
青灯夜游asal
2022-03-07 16:57:111215semak imbas

simbol ialah jenis baharu dalam es6. Simbol ialah jenis data asas baharu yang diperkenalkan dalam ECMAScript6, yang mewakili nilai unik Nilai jenis simbol yang perlu dijana menggunakan fungsi Symbol().

Adakah simbol jenis baru dalam es6?

Persekitaran pengendalian tutorial ini: sistem Windows 7, versi JavaScript 1.8.5, komputer Dell G3.

Simbol ialah jenis data baharu yang diperkenalkan dalam ECMAScript6 yang mewakili nilai unik; ia membawa beberapa faedah kepada JS, terutamanya apabila ia berkaitan dengan sifat objek. Tetapi apakah yang boleh mereka lakukan untuk kita yang tidak boleh dilakukan oleh rentetan?

Latar Belakang

Jenis data dalam js secara amnya terbahagi kepada dua jenis iaitu: nilai jenis dan rujukan

taip

Jenis nilai (jenis asas)

: Jenis angka (Nombor), jenis aksara (String), jenis Boolean (Boolean), nol dan ditakrifkan
  • Jenis rujukan (kelas) : fungsi, objek, tatasusunan, dsb.
  • ** Pemahaman jenis nilai: ** Tugasan bersama antara pembolehubah merujuk kepada membuka ruang memori kawasan baharu , tetapkan nilai pembolehubah kepada pembolehubah baharu dan simpannya dalam memori yang baru dibuka perubahan seterusnya dalam nilai dua pembolehubah tidak akan menjejaskan satu sama lain, contohnya:
Sesetengah bahasa, seperti C, mempunyai hantaran rujukan dan konsep lulus mengikut nilai. JavaScript mempunyai konsep yang sama di mana ia disimpulkan berdasarkan jenis data yang diluluskan. Jika nilai dihantar ke fungsi, menetapkan semula nilai tidak mengubah suai nilai dalam lokasi panggilan. Walau bagaimanapun, jika anda mengubah suai jenis rujukan, nilai yang diubah suai juga akan diubah suai di mana ia dipanggil.

** Pemahaman jenis rujukan: ** Tugasan bersama antara pembolehubah hanyalah pertukaran penunjuk, bukannya menyalin objek (objek biasa, objek fungsi, objek tatasusunan) ke pembolehubah baharu, objek kekal Terdapat masih hanya satu, hanya satu panduan lagi~~; contohnya:
var a = 10; //开辟一块内存空间保存变量a的值“10”;
var b = a; //给变量 b 开辟一块新的内存空间,将 a 的值 “10” 赋值一份保存到新的内存里;
//a 和 b 的值以后无论如何变化,都不会影响到对方的值;

Jenis nilai (kecuali nilai NaN yang misteri) akan sentiasa sama dengan jenis nilai lain dengan nilai yang sama, seperti berikut :

var a = { x: 1, y: 2 }; //需要开辟内存空间保存对象,变量 a 的值是一个地址,这个地址指向保存对象的空间;
var b = a; // 将a 的指引地址赋值给 b,而并非复制一给对象且新开一块内存空间来保存;
// 这个时候通过 a 来修改对象的属性,则通过 b 来查看属性时对象属性已经发生改变;
Tetapi jenis rujukan dengan struktur yang sama tidak sama:

const first = "abc" + "def";
const second = "ab" + "cd" + "ef";
console.log(first === second); // true
Objek memainkan peranan penting dalam bahasa JavaScript, dan ia digunakan di mana-mana sahaja. Objek sering digunakan sebagai koleksi pasangan kunci/nilai, walau bagaimanapun, menggunakannya dengan cara ini mempunyai had yang besar: sebelum

simbol

muncul, kunci objek hanya boleh menjadi rentetan dan jika anda cuba menggunakan bukan aksara Nilai rentetan sebagai kunci objek, maka nilai itu akan dipaksa menjadi rentetan, seperti berikut:
const obj1 = { name: "Intrinsic" };
const obj2 = { name: "Intrinsic" };
console.log(obj1 === obj2); // false
// 但是,它们的 .name 属性是基本类型:
console.log(obj1.name === obj2.name); // true

Apakah Simbol

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' }

Simbol () Fungsi mengembalikan nilai simbol jenis, yang mempunyai sifat statik dan kaedah statik. Sifat statiknya mendedahkan beberapa objek ahli terbina dalam; kaedah statiknya mendedahkan pendaftaran simbol global dan serupa dengan kelas objek terbina dalam, tetapi sebagai pembina ia tidak lengkap kerana ia tidak menyokong sintaks:

. Jadi nilai yang dijana menggunakan Simbol tidak sama:

Apabila membuat instantiation "new Symbol()"simbol

, terdapat argumen pertama pilihan yang anda boleh berikan rentetan secara pilihan. Nilai ini bertujuan untuk digunakan untuk kod nyahpepijat, jika tidak, ia tidak akan menjejaskan
const s1 = Symbol();
const s2 = Symbol();
console.log(s1 === s2); // false
simbol

itu sendiri. simbol sebagai atribut objek

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)

simbol mempunyai kegunaan penting lain, ia boleh digunakan sebagai kunci dalam objek, seperti berikut:

Pada pandangan pertama ini kelihatan seperti anda boleh mencipta sifat peribadi pada objek menggunakan

simbol

, banyak bahasa pengaturcaraan lain mempunyai sifat peribadi mereka sendiri dalam kelas mereka, peninggalan harta persendirian sentiasa dianggap Kelemahan JavaScript.
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']

Malangnya, kod yang berinteraksi dengan objek ini masih boleh mengakses sifatnya yang kuncinya ialah simbol . Ini juga boleh dilakukan dalam kes di mana kod panggilan belum mempunyai akses kepada simbol itu sendiri. Contohnya, kaedah boleh mendapatkan senarai semua kekunci pada objek, termasuk rentetan dan simbol:

Reflect.ownKeys() Nota: Pada masa ini terdapat beberapa kerja sedang dilakukan untuk mengendalikan penambahan sifat peribadi kepada kelas dalam masalah JavaScript. Nama ciri ini dipanggil

Medan Persendirian
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
, dan walaupun ini tidak akan memberi manfaat kepada semua objek, ia akan memanfaatkan objek yang merupakan tika kelas. Medan peribadi tersedia bermula dalam Chrome 74.

Menghalang perlanggaran nama harta Notasi

mungkin tidak mendapat manfaat secara langsung daripada JavaScript yang menyediakan sifat peribadi untuk objek. Walau bagaimanapun, mereka memberi manfaat atas sebab lain. Ia berguna apabila perpustakaan yang berbeza ingin menambah sifat pada objek tanpa risiko konflik nama. Simbol Agak sukar untuk menyediakan sifat peribadi untuk objek JavaScript, tetapi Simbol mempunyai kelebihan lain, iaitu untuk mengelakkan risiko konflik penamaan apabila perpustakaan berbeza menambah sifat pada objek.

考虑这样一种情况:两个不同的库想要向一个对象添加基本数据,可能它们都想在对象上设置某种标识符。通过简单地使用 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前端

Atas ialah kandungan terperinci Adakah simbol jenis baru dalam es6?. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn