《现代 JavaScript 教程 》Symbol

Symbol类型作为ES5新增的一种基本数据类型。每个从Symbol()返回的symbol值都是唯一的。Symbol不支持语法"new Symbol()"

const symbol1 = Symbol();
const symbol2 = Symbol(42);
const symbol3 = Symbol('foo');

console.log(typeof symbol1);
// expected output: "symbol"

console.log(symbol2
=== 42);
// expected output: false

console.log(symbol3.toString());
// expected output: "Symbol(foo)"

console.log(Symbol(
'foo') === Symbol('foo'));
// expected output: false

JavaScript中大多数数值类型支持字符串的隐式转换,但Symbol比较特殊,不会被自动转换为字符串。

如果想返回当前 symbol 对象的字符串表示,请使用Symbol.prototype.toString()

Symbol("desc").toString();   // "Symbol(desc)"

// well-known symbols
Symbol.iterator.toString(); // "Symbol(Symbol.iterator)

// global symbols
Symbol.for("foo").toString() // "Symbol(foo)"

description 是一个只读属性,它会返回 Symbol 对象的可选描述的字符串。

console.log(Symbol('desc').description);
// expected output: "desc"

console.log(Symbol.iterator.description);
// expected output: "Symbol.iterator"

console.log(Symbol.for('foo').description);
// expected output: "foo"

console.log(`${Symbol('foo').description}bar`);
// expected output: "foobar"

“隐藏”属性

Symbol允许我们创建对象的“隐藏”属性,代码的任何其他部分都不能意外访问或重写这些属性。

使用 Symbol("id") 作为键,比起用字符串 "id" 来有什么好处呢? 因为 user 对象属于其他的代码,那些代码也会使用这个对象,所以我们不应该在它上面直接添加任何字段,这样很不安全。但是你添加的 Symbol 属性不会被意外访问到,第三方代码根本不会看到它,所以使用 Symbol 基本上不会有问题。

如果我们要在对象字面量 {...} 中使用 Symbol,则需要使用方括号把它括起来。

let id = Symbol("id");

let user = {
name:
"John",
[id]:
123 // 而不是 "id":123
};

Symbol 属性不参与 for..in 循环,Object.keys(user) 也会忽略它们

为什么es6里的object不可迭代? - 知乎 (zhihu.com)

Object.assign()方法用于将所有可枚举属性的值从一个或多个源对象分配到目标对象。它将返回目标对象。String类型和 Symbol 类型的属性都会被拷贝。

全局Symbol

Symbol.for(key) 方法会根据给定的键 key,来从运行时的 symbol 注册表中找到对应的 symbol,如果找到了,则返回它,否则,新建一个与该键关联的 symbol,并放入全局 symbol 注册表中。它可以确保每次访问相同名字的 symbol 时,返回的都是相同的 symbol 。

Symbol.for("foo"); // 创建一个 symbol 并放入 symbol 注册表中,键为 "foo"
Symbol.for("foo"); // 从 symbol 注册表中读取键为"foo"的 symbol

Symbol.for("bar") === Symbol.for("bar"); // true,证明了上面说的
Symbol("bar") === Symbol("bar"); // false,Symbol() 函数每次都会返回新的一个 symbol

var sym = Symbol.for("mario");
sym.toString();
// "Symbol(mario)",mario 既是该 symbol 在 symbol 注册表中的键名,又是该 symbol 自身的描述字符串

类似的,对于全局Symbol,不仅有 Symbol.for(key) 按名字返回一个 Symbol,还有一个反向调用:Symbol.keyFor(sym)方法用来获取全局symbol 注册表中与某个 symbol 关联的键。

// 创建一个全局 Symbol
var globalSym = Symbol.for("foo");
Symbol.keyFor(globalSym); // "foo"

var localSym = Symbol();
Symbol.keyFor(localSym);
// undefined,

// 以下Symbol不是保存在全局Symbol注册表中
Symbol.keyFor(Symbol.iterator) // undefined

系统Symbol

JavaScript 内部有很多“系统” Symbol

Symbol.asyncIterator 符号指定了一个对象的默认异步迭代器。如果一个对象设置了这个属性,它就是异步可迭代对象,可用于for await...of循环。

Symbol.prototype.description 是一个只读属性,它会返回 Symbol 对象的可选描述的字符串。

Symbol.hasInstance 用于判断某对象是否为某构造器的实例。因此你可以用它自定义 instanceof 操作符在某个类上的行为。

Symbol.isConcatSpreadable 符号用于配置某对象作为Array.prototype.concat()方法的参数时是否展开其数组元素。

Symbol.iterator 为每一个对象定义了默认的迭代器。该迭代器可以被 for...of 循环使用。

Symbol.match 指定了匹配的是正则表达式而不是字符串。

Symbol.matchAll 返回一个迭代器,该迭代器根据字符串生成正则表达式的匹配项。

Symbol.replace 这个属性指定了当一个字符串替换所匹配字符串时所调用的方法。

Symbol.search Symbol.search 指定了一个搜索方法,这个方法接受用户输入的正则表达式,返回该正则表达式在字符串中匹配到的下标。

Symbol.species 是个函数值属性,其被构造函数用以创建派生对象。

Symbol.split 指向 一个正则表达式的索引处分割字符串的方法。

Symbol.toPrimitive 是一个内置的 Symbol 值,它是作为对象的函数值属性存在的,当一个对象转换为对应的原始值时,会调用此函数。

Symbol.toStringTag 是一个内置 symbol,它通常作为对象的属性键使用,对应的属性值应该为字符串类型,这个字符串用来表示该对象的自定义类型标签,通常只有内置的 Object.prototype.toString() 方法会去读取这个标签并把它包含在自己的返回值里。

Symbol.unscopables 指用于指定对象值,其对象自身和继承的从关联对象的 with 环境绑定中排除的属性名称。

原文地址:https://www.cnblogs.com/GodZhuan/p/15424436.html