本节将会重点分析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. easyui_validatebox常用验证

    $.extend($.fn.validatebox.defaults.rules, { idcard: {// 验证身份证 validator: function (value) { return / ...

  2. 转 jquery获取两个标签之间文本

    https://blog.csdn.net/u010403387/article/details/44197629?utm_source=blogxgwz8 如以下代码所示,id为tidy的<a ...

  3. Windows和Office激活汇总

    Windows和Office是常用的软件.多数情况下,即使不激活,也会使用一部分功能.今天来看一下很多前辈的工作成果. 1. Windows 7&10 1.1 永久激活 通过key 分享几个常 ...

  4. 了解ip相关知识

    最近一直扫盲,作为一个编程工作者,其实涉及的东西很广,但也一直没有深入一些网络的概念. 内内网IP局域网,网线都是连接在同一个 交换机上面的,也就是说它们的IP地址是由交换机或者路由器进行分配的.而且 ...

  5. BAT:通过连接符处理判断OR的关系

    使用情况说明: 适用于对某个文件夹下不同的文件夹(名称)做不同的处理,但存在需要对其中多个文件夹(名称)进行相同处理的情况 例子中的目录结构: .\1.2.3 -- 文件夹.\a.b.c -- 文件夹 ...

  6. pdo的简单介绍和使用

    1,PDO的定义:php data object(php数据对象); 2,连接pdo的相关参数:$dsn.$user.$pass. 其中$dsn="mysql:host=$host;dbna ...

  7. Ubuntu 16.04.2 配置VNC

    1安装包apt-get update sudo apt install xfce4 xfce4-goodies tightvncserversudo apt-get install vnc4serve ...

  8. javaWeb中MVC的编程思想示例

    没有学习MVC之前我只写了一个Servlet类(Note_List.java),分层之后,我将这个类分成了5个类(NoteDao.java,,NoteDaoImpl.java,,NoteService ...

  9. CentOS5.5 - lnmp环境安装与使用

    CentOS5.5 - lnmp环境安装与使用 到公司搭建环境可以直接使用YUM. 安装一.rpm包安装(安装方便) yum:下载软件包并且安装.前提:连网. yum 使用流程: 1. yum lis ...

  10. mysql5.6版本的优化

    1. 目标 l 了解什么是优化 l 掌握优化查询的方法 l 掌握优化数据库结构的方法 l 掌握优化MySQL服务器的方法 2. 什么是优化? l 合理安排资源.调整系统参数使MySQL运行更快.更节省 ...