本节将会重点分析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. centos7 Mycat/MySQL/MariaDB安装部署

    使用yum安装MySQL详细步骤 安装mysql源 centos系统中不包含mysql的源,需要先安装mysql源 1.官网下载源.使用图形界面操作系统进入mysql官网,进入以下界面. 2.在Cen ...

  2. vs C++ scanf 不安全

    项目->属性-> c/c++->预处理器->预处理器定义->加入下面这句: _CRT_SECURE_NO_DEPRECATE

  3. MapGIS DataStore

    http://www.mapgis.com/index.php/index-show-tid-206.html 异构数据同时加载 DCServer感觉已经集成到 IGServer中了. >> ...

  4. C++输出格式

    C++输出格式 C++中默认输出有效位数是6位,即 则输出: 221.111.11011199967 //6位有效数字,自动截取保存六位1.99967e+006 //六位以上且无法省略显示将会变为指数 ...

  5. one-to-one 一对一映射关系(转 wq群)

    2.配置对应的xml配置文件 person的配置文件 idCard的配置文件 idCard的配置文件  3.测试 运行测试程序后,控制台输出两条语句

  6. linux sshd 登录不需要密码

    ssh 安全外壳协议 协议22 linux 默认放行了 22 号接口 ssh 默认安装 自行安装 应该是 openssh-server ssh命令是 openssh ssh-keygen 生成密钥 生 ...

  7. 利用UiWatchers 监听解决安卓自动化各种自动化各种非期待弹窗,弹层,升级,广告,对话框,来电等问题

    app自动化时,各种不期待的弹层弹窗,升级广告等时有飞出,由于弹窗具有不定时,不定页面等很多不确定性.有的弹窗很不友好,不×掉,很难进行下一步操作,造成 测试用例失败.而判断是否有弹窗,弹层很麻烦.研 ...

  8. POM文件详解(2)

    1      项目构建 <!-- 构建项目需要的信息 --> <build> <!-- 子项目可以引用的默认插件信息.该插件配置项直到被引用时才会被解析或绑定到生命周期. ...

  9. 论文word排版相关插件

    其中包括破解版的MathType.EndNote X7以及Aurora 链接:http://pan.baidu.com/s/1boRZTmf 密码:a6ai

  10. mysql5.6版本的优化

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