他们称之为知名符号 — 尽管大多数开发者从未使用过它们,甚至从未听说过它们。
这是一个非常酷的功能,你可以用它来实现这样的魔法:
你将看到我们如何使用知名 Symbol 构建这些类来实现这一点。
它们全都是关于完全定制内置操作(如for..of
)的正常行为。这就像C++和C#中的运算符重载。
它们也都是Symbol
类的静态方法。
1. Symbol.hasInstance
首先我们有Symbol.hasInstance
:用于轻松改变instanceof
运算符的行为。
通常,instanceof
用于检查一个变量是否是某个类的实例。
就像它应该的那样;相当标准的东西。
但是使用Symbol.hasInstance
,我们可以完全改变instanceof
的工作方式:
现在就instanceof
而言,一个Person
不再是Person
了。
如果我们不想完全覆盖它,而是以一种直观的方式扩展它呢?
我们不能在 Symbol 内部使用instanceof
,因为那会很快导致无限递归:
class Person {
static [Symbol.hasInstance](instance) {
return instance instanceof Person; // 无限递归!
}
}
相反,我们将对象的特殊constructor
属性与我们自己的进行比较:
如果你刚刚听说.constructor
,这应该解释一切:
2. Symbol.iterator
我们的下一个黑客技巧是Symbol.iterator
,用于完全改变循环如何以及是否在对象上工作。
还记得这个吗:
我们通过Symbol.iterator
实现了这一点:
我们再次看到生成器出现。
每当我们使用for..of
时
这在幕后发生:
因此,通过Symbol.iterator
,我们完全改变了for..of
对任何List
对象的操作:
3. Symbol.toPrimitive
使用Symbol.toPrimitive
,我们可以快速从这个:
变成这个:
我们通过覆盖Symbol.toPrimitive
实现了这一点:
现在我们可以在任何使用字符串进行插值和连接的地方使用Person
对象:
甚至还有一个hint
参数,可以使对象表现得像number
、string
或其他东西。
4. Symbol.split
天才的知名 Symbol,用于将你的自定义对象转换为字符串分隔符:
5. Symbol.search
就像Symbol.split
一样,将你的自定义对象转换为复杂的字符串搜索工具:
最后的思考
从循环到分割再到搜索,知名符号让我们可以重新定义我们的核心功能,使它们以独特和令人愉快的方式运行,推动了JavaScript可能性的边界。