ES6新数据类型Symbol

来源:互联网 发布:怎样提升淘宝信用度 编辑:程序博客网 时间:2024/06/10 09:20

Symbol 

今年最火的莫过于 ES6 + Babel 了。ES6 引入了一些很实用很强大的特性和一些语法。今天说的 Symbol 就是其中一个。

对于这个新特性,很多人估计很少使用它,尤其是可见性封装特别好的时候。但它也有很应用场景的。
那Symbol 到底是个什么东西呢?

数据类型

首先它是 ES6 引入的一个 JS 数据类型。熟悉 JavaScript 的都知道,JavaScript 有七大数据类型。

null, undefined, number, boolean, string, Array、object// 基本数据类型:null、undefined、数字、布尔、字符串// 复杂数据类型: 数组、对象等
而Symbol 就是类似这些的一种数据类型。利用 typeof 运算符它的结果如下:

typeof Symbol() === 'symbol'// 为 true

现在已经定位它是什么了,那它有什么用呢?
Symbol() 用于解决属性名的冲突。比如,对于同一个对象 obj,A 对其加了属性 a, 之后B修改代码也想对其加属性 a,此时如果不知情的情况下就会产生覆盖问题。
举个应用场景,比如一个人名叫“张三”,他可能拥有两个国家甚至更多国家的国籍,因此会有多个身份 Id号。此时我们直观的做法就是加 Id 属性:

var person = {name: "zhangsan",id: "XXXXX", // 可能多个age: 20}
也会有人说,用数组就好,那每个国家的 id 怎么获取?
var person = {name: "zhangsan",id: ["XXXXX", 'YYYYY'] // 哪个是中国人身份证的 id ?age: 20}
此时若是用 Symbol 便能很好的解决问题。因为传入对象属性时,同样的Symbol不相等。看下面:
Symbol('key') === Symbol('key')  // false, 因为Symbol('key') 
Symbol('key') 两次的返回值是不同的,且是独一无二的值。

现在解决上面的问题。

var person = {name: "zhangsan",age: 20}// Symbol('key') 生成引用类型,独一无二的,所以 chinaId 与 americaId 不等。var chinaId = Symbol('id');var americaId = Symbol('id');person[chinaId] = "chinaId";person[americaId] = "americaId";

如下:



语法

生成一个 Symbol 很容易, 直接调用 Sysmbol() 即可,当然也可以传个参数作为描述。

var sym = Symbol();// 参数: 只是个描述// 只是为了在控制台显示,或者转为字符串时,比较容易区分var sym2 = Symbol('I am just a description');sym2.toString()// "Symbol(I am just a description)"
另外,还可以用 Symbol.for 生成一个 Symbol

var keySym = Symbol.for('key');
只是这里有点不同于上面:

Symbol.for('key') === Symbol.for('key');// 这里为  true
这说明,两次使用 Symbol.for('key') 生成的结果一样。
Symbol.for()与Symbol()这两种写法,都会生成新的Symbol。它们的区别是,前者会在全局环境中供搜索,后者不会。Symbol.for()不会每次调用就返回一个新的 Symbol 类型的值,而是会先检查给定的key是否已经存在,如果不存在才会新建一个值。因此这里的参数与生成的 Symbol 有关。两种方式用于不同的场景。
var keySym = Symbol.for('key');Symbol.keyFor(keySym) // "key"


特性

独一无二

这个特性上面已经说了,每次 调用 Symbol('key') 都会产生一个独一无二的值。比如调用 Symbol('key')  10次,就会得到 10 个 Symbol 类型的对象。

存取

读取和修改都很方便,只是不能用 obj.prop 的形式访问。注意,这里是修改 对象的 Symbol 类型的属性。

console.log(person[chinaId]); // okperson[chinaId] = "zhangsanId";// okconsole.log(person.chinaId); // 输出 undefined
虽然不能用 obj.prop 形式访问,但还是可以用下面三种方式的。

var obj = {};var symProp = Symbol();// 第一种var obj = {  [symProp]: 'YYYY'};// 第二种obj[symProp] = 'XXXX';// 第三种写法Object.defineProperty(obj, symProp, { value: 'ZZZZ' });


只读

对应 Symbol 类型的对象,它是只读的。对它添加属性不起作用。

Symbol("key").name = 1; // 文档里说会 TypeError// 不过我在 Chrome 控制台使用时发现,只是不起作用而已。
下面是个例子:

var sb = Symbol('key');sb.name = "zw";console.log(sb);console.log(sb.name);

上面代码中,我们对 Symbol('key') 的 name 属性赋值, 然后访问,只得到 undefined .

遍历

我们给对象添加了 Symbol() 属性,不过它终归不是普通属性。像 for...in 、 Object.keys(obj) 、Object.getOwnPropertyNames(obj)会忽略Symbol,即属性自身不可枚举。
var person = {name: "zhangsan",age: 20}var chinaId = Symbol('id');person[chinaId] = "chinaId";for( var prop in person) {console.log(person[prop]);}Object.keys(person);Object.getOwnPropertyNames(person);

从上图看,三种遍历确实只访问了 两个基本属性,而Symbol 属性被忽略。

那怎么遍历呢?两个方法:

Object.getOwnPropertySymbols(person) //获取Symbol属性名,但是也会忽略内置的SymbolReflect.ownKeys(obj) //获取所有的属性名


另外,它还有一些实用的属性和方法,有兴趣的可以自己尝试下。官网