Symbols是什么了?它是JavaScript中的第七种原始类型
JavaScript原始类型(值类型):String、Null、Undefined、Number、Boolean+Symblos
引用数据类型:Object,Array,Function
布尔类型只有两个值, true和 false,不会再创造第三种布尔值;数字类型和字符串类型的值更多,标准指明一共
有 18,437,736,874,454,810,627 种不同的数字(包括 NaN, 亦即“Not a Number”的缩写,代表非数字),可能存在的字符串类型的值拥有无以匹敌的数量,大约是(2144,115,188,075,855,872 - 1) ÷ 65,535 种、可能得出了一个错误的答案,但字符串类型值的集合一定是有限的,对象类型值的集合是无限的。
从一个简单的布尔类型出发
当需要把别人外部函数存储到一个JavaScript对象中,例如判断CSS样式是否移动:创建一个标记
if (element.isMoving) {
smoothAnimations(element);
}
element.isMoving = true;
这样也会有一些潜在的问题,事实上,上述代码很可能不是唯一一段操作 DOM 的代码。
可能会自定名称,比如:
if
(element.__$jorendorff_animation_library$PLEASE_DO_NOT_USE_THIS_PROPERTY$isMovi
ng__) {
smoothAnimations(element);
}
element.__$jorendorff_animation_library$PLEASE_DO_NOT_USE_THIS_PROPERTY$isMovin
g__ = true;
但是易读性太低,或者用密码学创建一个唯一的属性名称:
// 获取 1024 个 Unicode 字符的无意义命
var isMoving = SecureRandom.genera
...
if (element[isMoving]) {
smoothAnimations(element);
}
element[isMoving] = true;
object[name]代码几乎不可能冲突,但是调试的时候会输出一长串乱序字符串。如何解决这个问题了?
symbol 是最终的解决方案
symbol 是程序创建并且可以用作属性键的值,并且它能避免命名冲突的风险
var nativeSymbol =Symbol(); //nativeSymbol的值与其他值不等
字符串或数字可以作为属性的键, symbol 也可以,它不等同于任何字符串,因而这个以 symbol 为键的属性可以保证不与任何其它属性产生冲突。
var obj ={state:11} ;
nativeSymbol =Symbol();
obj[nativeSymbol] = "ok";
console.log(obj[nativeSymbol]); //ok
上面的情况就可以改为:
// 创建一个独一无二的 symbol
var isMoving = Symbol("isMoving");
...
if (element[isMoving]) {
smoothAnimations(element);
}
element[isMoving] = true;
Symbol("isMoving")中的 isMoving 被称作描述。element[isMoving]被称作一个以 symbol 为键(symbol-keyed)的属性。
它是symbol不是字符串,除此之外它与一个普通的属性没有什么区别。以 symbol 为键的属性属性与数组元素类似,不能被类似 obj.name 的点号法访问,你必须使用方括号访问这些属性。查看属性是否存在: if (isMoving in element),也可以删除属性: deleteelement[isMoving]。同时symbol创建的ismoving只有在当前作用域中才有效,这是symbol的弱封装机制。创建的symbol可在任意对象上使用,无需担心其他代码创建的属性产生冲突。
symbol 键的设计初衷是避免初衷,因此 JavaScript 中最常见的对象检查的特性会忽略 symbol 键。例如, for-in 循环只会遍历对象的字符串键, symbol 键直接跳过,Object.keys(obj)和 Object.getOwnPropertyNames(obj)也是一样。但是 symbols 也不完全是私有的:用新的 APIObject.getOwnPropertySymbols(obj)就可以列出对象的symbol 键。另一个新的 API,Reflect.ownKeys(obj),会同时返回字符串键和 symbol键。
但是,Symbol是什么?
控制台下测试symbol是什么,得到如下结果
symbol被创建后不可更改,不能设置属性,Strict模式下会得到TypeError错误,每个symbol都独一无二
关于Symbol的忠告:symbol 不能被自动转换为字符串,这和语言中的其它类型不同。尝试拼接 symbol 与字符串将得到 TypeError 错误
var mySymbol = Symbol("Symbol");
var str = "your symbol is " +mySymbol;
var str2 = `you symbol is ${mySymbol}`;
//解决方法
var str3 = "your symbol is " +mySymbol.toString();
var str4 = `you symbol is ${mySymbol.toString()}`;
可以通过String(mySymbol)或者mySymbol.toString();解决
获取 symbol 的三种方法
- 调用Symbol() ,每次返回一个新的唯一Symbol;
- 调用Symbol.for(string) 这种方式会访问 symbol 注册表,其中存储了已经存在的一系列 symbol。这种方式与通过 Symbol()定义的独立 symbol 不同, symbol 注册表中的 symbol 是共享的。如果你连续三十次调用 Symbol.for("cat"),每次都会返回相同的 symbol。注册表非常有用,在多个 web 页面或同一个 web 页面的多个模块中经常需要共享一个 symbol;
- 使用标准的symbol,例如Symbol.Iterator
symbol 在 ES6 规范中的应用
- 使 instanceof 可扩展,在 ES6 中,表达式 object instanceof constructor 被指定为构造函数的一个方法: constructor[Symbol.hasInstance](object)。这意味着它是可扩展的;
- 消除新特性和旧代码之间的冲突。破坏问题主要由动态作用域引起,所以 ES6 引入一个特殊的 symbol——Symbol.unscopables, Web 标准可以用这个 symbol 来阻止某些方法别加入到动态作用域中;
- 支持新的字符串匹配类型。在 ES5 中, str.match(myObject)会尝试将 myObject 转换为正则表达式对象(RegExp)。在 ES6 中,它会首先检查 myObject 是否有一个myObject[Symbol.match](str)方法。
本文参考《ES6-In-Depth》