本节将会重点分析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. python之支付

    一,alipay方式 1,国内的alipay支付:我在网上找了好多的教程,大多数都是属于国内内支付的,所以在这里我就不详细介绍了, 操作:https://www.cnblogs.com/xuanan/ ...

  2. MySQL系统变量 sql_mode 详解

    转载自:http://tech.it168.com/a2012/0822/1388/000001388401_all.shtml MySQL数据类型:SQL_MODE设置不容忽视 SQL_MODE可能 ...

  3. openmp入门总结

    Ref: https://wdxtub.com/2016/03/20/openmp-guide/ 简介 这门课作为 ECE 中少有的跟计算机科学相关的课,自然是必上不可.不过无论是 OpenMP 还是 ...

  4. 数据结构C语言版-栈

    #include <stdio.h> #include <stdlib.h> #include <math.h> #include <iostream> ...

  5. 通过TensorFlow训练神经网络模型

    神经网络模型的训练过程其实质上就是神经网络参数的设置过程 在神经网络优化算法中最常用的方法是反向传播算法,下图是反向传播算法流程图: 从上图可知,反向传播算法实现了一个迭代的过程,在每次迭代的开始,先 ...

  6. appium selenium.common.exceptions.WebDriverException: Message: Parameters were incorrect

    selenium.common.exceptions.WebDriverException: Message: Parameters were incorrect. We wanted {" ...

  7. Verilog有符号数处理

    内容主要摘自以下两个链接:  https://www.cnblogs.com/LJWJL/p/3481995.html  https://www.cnblogs.com/LJWJL/p/3481807 ...

  8. 解答VS2013编译报错不准确是什么原因

    1.当程序在错误时,VS2013编译报出的错误有时不会一起全部报出,而是按错误的英文首字母逐个报出的 2.如果报错的信息双击点过去查看时又发现无明显错误问题时,这个这个时候可以是VS编译的缓存问题,这 ...

  9. 计算机网络六:无线局域网、IEEE 802.11、WIFI和蓝牙

    无线局域网.IEEE 802.11.WIFI和蓝牙 ㈠无线局域网 1.定义       无线局域网络(Wireless Local Area Networks),简称WLAN.它是相当便利的数据传输系 ...

  10. 使用koa2+es6/7打造高质量Restful API

    前言 如今nodejs变得越来越火热,采用nodejs实现前后端分离架构已被多数大公司所采用. 在过去,使用nodejs大家首先想到的是TJ大神写的express.js,而发展到如今,更轻量,性能更好 ...