ES6躬行记(6)——Symbol
本节将会重点分析ES6引入的第6种基本类型:Symbol(符号)。符号可以像字符串那样作为对象的属性名,只是它有唯一性的特点,可以避免属性名之间的冲突。
一、创建
符号没有字面量形式,只能通过Symbol()函数创建。该函数有一个可选的参数,只是用来描述当前符号,除了便于阅读之外,没有其他用途。由此可知,即使两个符号的描述相同,它们还是不能画等号。注意,Symbol()不是构造函数,因此不能和new运算符组合使用,否则会抛出类型错误。下面用一个例子展示符号的创建。
var sym1 = Symbol(),
sym2 = Symbol("name"),
sym3 = Symbol("name"),
sym4 = new Symbol(); //抛出类型错误
console.log(sym2 === sym3); //false
如果要识别一个变量是否为符号,可以用typeof运算符。ES6扩展了它,当检测到符号时,能返回一个新的类型字符串“symbol”,具体如下所示。
typeof sym1; //"symbol"
typeof sym2; //"symbol"
二、类型转换
符号在类型转换时表现得并不灵活,它无法与数字或字符串进行运算,也无法显式的转换成数字。如下所示,后面四条语句在执行时都会报错。
var sym = Symbol("age");
Number(sym);
parseInt(sym);
1 + sym;
"" + sym;
不过,符号可以显式的转换成字符串或布尔值,具体如下所示。
Boolean(sym); //true
!sym; //false
sym.toString(); //"Symbol(age)"
String(sym); //"Symbol(age)"
三、全局共享
ES6会在内部维护一张全局符号注册表,通过Symbol.for()方法,可以登记指定符号,使其变成一个全局有效地符号,从而达到全局共享。该方法只接收一个参数,这个参数既是注册表中的键值,同时也是此符号的描述。下面的代码调用了两次Symbol.for()方法,传递了相同的参数,返回的却是同一个全局符号。
var sym1 = Symbol.for("name"),
sym2 = Symbol.for("name");
console.log(sym1 === sym2); //true
在上面的代码中,第一次调用Symbol.for()方法时,会在注册表中搜索键值为“name”的符号,由于没有找到,所以就会创建一个新的符号。而在第二次调用Symbol.for()方法时,由于传递的键值与前一次相同,因此会返回刚刚的那个符号。从而可知,对变量sym1和sym2进行全等比较,返回的结果将是true。
如果要获取某个全局符号所对应的键值(即它的描述),那么可以通过Symbol.keyFor()实现,具体操作如下所示。
Symbol.keyFor(sym1); //"name"
Symbol.keyFor(sym2); //"name"
四、属性名
本节开头曾提到过对象的属性名可以用符号表示,而这类属性可以有三种赋值方式。第一种是用方括号,注意,不能用点号,因为点号后面的标识符会被识别成字符串而不是符号。下面代码分别用方括号和点号为obj对象的sym属性赋值,前者被识别成了符号属性,而后者却被识别成了字符串属性。
var sym = Symbol("name"),
obj = {};
obj[sym] = "strick";
obj.sym = "strick";
console.log(obj); //{Symbol(name): "strick", sym: "strick"}
第二种是在创建对象字面量时,用计算属性名的方式(即属性名被方括号包裹)为其赋值,如下所示。
obj = {
[sym]: "freedom"
};
第三种是调用Object.defineProperty()或Object.defineProperties()方法来为符号属性赋值,如下所示。
Object.defineProperty(obj, sym, { value: "justice" });
注意,符号属性是不可枚举的,既不能被for-in等循环遍历到,也不能被Object.keys()、Object.getOwnPropertyNames()等方法读取到。但可以通过Object.getOwnPropertySymbols()方法获得对象的符号属性,具体如下所示。
obj = {
[sym]: "freedom",
age: 28
};
Object.keys(obj); //["age"]
Object.getOwnPropertyNames(obj); //["age"]
Object.getOwnPropertySymbols(obj); //[Symbol(name)]
五、内置符号
ES6提供了一些内置符号,也叫做知名符号(Well-Known Symbol)。它们暴露了语言的内部逻辑,允许开发人员修改或拓展规范所描述的对象特征或行为。每一个内置符号对应Symbol对象的一个属性,例如Symbol.hasInstance、Symbol.iterator等,表1列出了11个内置符号。
表1 内置符号
属性名称 | 值类型 | 描述 |
hasInstance | 方法 | 当使用instanceof运算符时会调用该方法 |
isConcatSpreadable | 布尔值 | 当对象作为Array.prototype.concat()方法的参数时,控制该对象是否被展开 |
iterator | 方法 | 返回一个迭代器,用于定义一个可迭代的对象 |
match | 方法 | 当对象作为String.prototype.match()方法的参数时,该方法会被调用 |
replace | 方法 | 当对象作为String.prototype.replace()方法的参数时,该方法会被调用 |
search | 方法 | 当对象作为String.prototype.search()方法的参数时,该方法会被调用 |
split | 方法 | 当对象作为String.prototype.split()方法的参数时,该方法会被调用 |
species | 方法 | 创建派生类的构造函数 |
toPrimitive | 方法 | 当对象需要转换成原始值(即执行ToPrimitive抽象操作)时,该方法会被调用 |
toStringTag | 字符串 | 指定对象的类型,可在调用Object.prototype.toString()方法的时候返回 |
unscopables | 对象 | 保存在这个对象中的属性将不能被with语句所引用 |
下面会给出4个内置符号的示例,分别是hasInstance、isConcatSpreadable、match和toStringTag。
let digit = {
[Symbol.hasInstance](number) {
return !(number % 2); //判断数字是否为偶数
}
};
1 instanceof digit; //false
2 instanceof digit; //true let arr1 = [3, 4];
[1, 2].concat(arr1); //[1, 2, 3, 4]
let arr2 = [3, 4];
arr2[Symbol.isConcatSpreadable] = false; //禁止展开
[1, 2].concat(arr2); //[1, 2, [3, 4]] let regex = {
[Symbol.match](str) {
return str.substr(0, 10);
}
},
message = "My name is strick";
message.match(regex); //"My name is" let people = {
[Symbol.toStringTag]: "People"
};
people.toString(); //"[object People]"
ES6躬行记(6)——Symbol的更多相关文章
- ES6躬行记 笔记
ES6躬行记(18)--迭代器 要实现以下接口## next() ,return,throw 可以用for-of保证迭代对象的正确性 例如 var str = "向
- ES6躬行记(1)——let和const
古语云:“纸上得来终觉浅,绝知此事要躬行”.的确,不管看了多少本书,如果自己不实践,那么就很难领会其中的精髓.自己研读过许多ES6相关的书籍和资料,平时工作中也会用到,但在用到时经常需要上搜索引擎中查 ...
- ES6躬行记(21)——类的继承
ES6的继承依然是基于原型的继承,但语法更为简洁清晰.通过一个extends关键字,就能描述两个类之间的继承关系(如下代码所示),在此关键字之前的Man是子类(即派生类),而在其之后的People是父 ...
- ES6躬行记(14)——函数
在前面的章节中,已陆陆续续介绍了ES6为改良函数而引入的几个新特性,本章将会继续讲解ES6对函数的其余改进,包括默认参数.元属性.块级函数和箭头函数等. 一.默认参数 在ES5时代,只能在函数体中定义 ...
- ES6躬行记(20)——类
ES6正式将类(Class)的概念在语法层面标准化,今后不必再用构造函数模拟类的行为.而ES6引入的类本质上只是个语法糖(即代码更为简洁.语义更为清晰),其大部分功能(例如继承.封装和复用等)均可在E ...
- ES6躬行记(19)——生成器
根据ES6制订的标准自定义迭代器实现起来比较复杂,因此ES6又引入了生成器的概念,生成器(Generator)是一个能直接创建并返回迭代器的特殊函数,可将其赋给可迭代对象的Symbol.iterato ...
- ES6躬行记(18)——迭代器
ES6将迭代器和生成器内置到语言中,不仅简化了数据处理和集合操作,还弥补了for.while等普通循环的不足,例如难以遍历无穷集合或自定义的树结构等. 迭代器(Iterator)是一种用于迭代的对象, ...
- ES6躬行记(17)——Map
一.Map Map类似于Object(对象),可用来存储键值对,但需要通过SameValueZero算法保持键的唯一性.与Set一样,在使用之前也得要实例化,如下代码所示,构造函数Map()中的参数也 ...
- ES6躬行记(16)——Set
ES6引入了两种新的数据结构:Set和Map.Set是一组值的集合,其中值不能重复:Map(也叫字典)是一组键值对的集合,其中键不能重复.Set和Map都由哈希表(Hash Table)实现,并可按添 ...
随机推荐
- SpringBoot+Mybatis配置Pagehelper分页插件实现自动分页
SpringBoot+Mybatis配置Pagehelper分页插件实现自动分页 **SpringBoot+Mybatis使用Pagehelper分页插件自动分页,非常好用,不用在自己去计算和组装了. ...
- JAVA 8 主要新特性 ----------------(七)新时间日期 API -----LocalDate
一.改版原因 1.老板的Date和Calander存在问题,日期操作名称混乱,有的在text下,有的在util下,包名混乱 2.Simple包混乱,致命错误线程不安全. ...
- deepCopy深拷贝
function deepCopy(p,c){ var c = c || {}; for ( var i in p ){ //确保属于自己的属性 if ( p.hasOwnProperty( i ) ...
- WSGI协议以及对服务器的影响
下面的内容纯属个人学习心得,如果对于我的观点有疑问,敬请留言,我将虚心向大牛学习. WSGI的全称是WEB SERVICE GATEWAY INTERFACE.WSGI 不是服务器,不是API,也不是 ...
- Python核心团队计划2020年停止支持Python2,NumPy宣布停止支持计划表
Python核心团队计划在2020年停止支持Python 2.NumPy项目自2010年以来一直支持Python 2和Python 3,并且发现支持Python 2对我们有限的资源增加了负担:因此,我 ...
- python中字典的操作
----------字典操作------------ --查字典1. 字典名["元素名称"]2. 字典名.get("元素名称")-获取不存在得元素名称,.get ...
- JS获取form表单数据
以下代码可放在一个js文件中,以便通用: //获取指定表单中指定标签对象 function getElements(formId, label) { var form = document.getEl ...
- jQuery-爱奇艺图片切换
<!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title>& ...
- iOS TouchID & FaceID
import UIKit import LocalAuthentication //指纹识别必须用真机测试,并且在iOS8以上系统,如果是FaceID至少IOS11以上. class Authenti ...
- eclipse安装及配置pydev
1.首先安装jre,这里记住jre的安装目录,32位操作系统默认安装在“C:\Program Files (x86)\Java\jre1.8.0_91” 2.配置eclipse,这里使用的是压缩包不需 ...