本节将会重点分析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的更多相关文章

  1. ES6躬行记 笔记

    ES6躬行记(18)--迭代器 要实现以下接口## next() ,return,throw 可以用for-of保证迭代对象的正确性 例如 var str = "向

  2. ES6躬行记(1)——let和const

    古语云:“纸上得来终觉浅,绝知此事要躬行”.的确,不管看了多少本书,如果自己不实践,那么就很难领会其中的精髓.自己研读过许多ES6相关的书籍和资料,平时工作中也会用到,但在用到时经常需要上搜索引擎中查 ...

  3. ES6躬行记(21)——类的继承

    ES6的继承依然是基于原型的继承,但语法更为简洁清晰.通过一个extends关键字,就能描述两个类之间的继承关系(如下代码所示),在此关键字之前的Man是子类(即派生类),而在其之后的People是父 ...

  4. ES6躬行记(14)——函数

    在前面的章节中,已陆陆续续介绍了ES6为改良函数而引入的几个新特性,本章将会继续讲解ES6对函数的其余改进,包括默认参数.元属性.块级函数和箭头函数等. 一.默认参数 在ES5时代,只能在函数体中定义 ...

  5. ES6躬行记(20)——类

    ES6正式将类(Class)的概念在语法层面标准化,今后不必再用构造函数模拟类的行为.而ES6引入的类本质上只是个语法糖(即代码更为简洁.语义更为清晰),其大部分功能(例如继承.封装和复用等)均可在E ...

  6. ES6躬行记(19)——生成器

    根据ES6制订的标准自定义迭代器实现起来比较复杂,因此ES6又引入了生成器的概念,生成器(Generator)是一个能直接创建并返回迭代器的特殊函数,可将其赋给可迭代对象的Symbol.iterato ...

  7. ES6躬行记(18)——迭代器

    ES6将迭代器和生成器内置到语言中,不仅简化了数据处理和集合操作,还弥补了for.while等普通循环的不足,例如难以遍历无穷集合或自定义的树结构等. 迭代器(Iterator)是一种用于迭代的对象, ...

  8. ES6躬行记(17)——Map

    一.Map Map类似于Object(对象),可用来存储键值对,但需要通过SameValueZero算法保持键的唯一性.与Set一样,在使用之前也得要实例化,如下代码所示,构造函数Map()中的参数也 ...

  9. ES6躬行记(16)——Set

    ES6引入了两种新的数据结构:Set和Map.Set是一组值的集合,其中值不能重复:Map(也叫字典)是一组键值对的集合,其中键不能重复.Set和Map都由哈希表(Hash Table)实现,并可按添 ...

随机推荐

  1. SpringBoot+Mybatis配置Pagehelper分页插件实现自动分页

    SpringBoot+Mybatis配置Pagehelper分页插件实现自动分页 **SpringBoot+Mybatis使用Pagehelper分页插件自动分页,非常好用,不用在自己去计算和组装了. ...

  2. JAVA 8 主要新特性 ----------------(七)新时间日期 API -----LocalDate

    一.改版原因 1.老板的Date和Calander存在问题,日期操作名称混乱,有的在text下,有的在util下,包名混乱         2.Simple包混乱,致命错误线程不安全.        ...

  3. deepCopy深拷贝

    function deepCopy(p,c){ var c = c || {}; for ( var i in p ){ //确保属于自己的属性 if ( p.hasOwnProperty( i ) ...

  4. WSGI协议以及对服务器的影响

    下面的内容纯属个人学习心得,如果对于我的观点有疑问,敬请留言,我将虚心向大牛学习. WSGI的全称是WEB SERVICE GATEWAY INTERFACE.WSGI 不是服务器,不是API,也不是 ...

  5. Python核心团队计划2020年停止支持Python2,NumPy宣布停止支持计划表

    Python核心团队计划在2020年停止支持Python 2.NumPy项目自2010年以来一直支持Python 2和Python 3,并且发现支持Python 2对我们有限的资源增加了负担:因此,我 ...

  6. python中字典的操作

    ----------字典操作------------ --查字典1. 字典名["元素名称"]2. 字典名.get("元素名称")-获取不存在得元素名称,.get ...

  7. JS获取form表单数据

    以下代码可放在一个js文件中,以便通用: //获取指定表单中指定标签对象 function getElements(formId, label) { var form = document.getEl ...

  8. jQuery-爱奇艺图片切换

    <!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title>& ...

  9. iOS TouchID & FaceID

    import UIKit import LocalAuthentication //指纹识别必须用真机测试,并且在iOS8以上系统,如果是FaceID至少IOS11以上. class Authenti ...

  10. eclipse安装及配置pydev

    1.首先安装jre,这里记住jre的安装目录,32位操作系统默认安装在“C:\Program Files (x86)\Java\jre1.8.0_91” 2.配置eclipse,这里使用的是压缩包不需 ...