Ignite

Symbol对象

2018-09-19

称符号对象,是es2015(也就是es6)中新添加的数据类型。通过Symbol()可以得到一个唯一的值,所以这个值很适合做标识符。

概念

Symbol() function 返回一个类型为symbol的值,Symbol有静态属性,原型上也有methods,但是缺少constructor,所以你不能new Symbol()来执行;

引用官方翻译,符号是一种特殊的、不可变的数据类型,它可以作为对象属性的标识符使用。符号对象是一个对的符号原始数据类型的隐式对象包装器。

  • 类型
1
2
let sym = Symbol(); // Symbol中参数为字符串,用来描述。
console.log(typeof sym); //"symbol"
  • 唯一性
1
2
3
4
5
const sym1 = Symbol('abc');
const sym2 = Symbol('cba');
console.log(sym1,sym2); //Symbol(abc) Symbol(cba)
//参数的作用就是描述,便于调试
console.log(sym1.toString()) //'Symbol(abc)'
  • new关键字
1
const sym = new Symbol(); // TypeError

获取symbol类型值的三种方式

  • 通过Symbol对象

也就是前面说的 let sym = Symbol();得到一个为一个的symbol值

  • Symbol.for(string)

可以注册一个symbol,再次调用Symbol.for(string)会得到这个symbol值,区别于Symbol()是唯一的

1
2
3
4
let sym = Symbol('abc');
const sym1 = Symbol.for('abc');
console.log(sym === sym1); //false
console.log(sym1 === Symbol.for('abc')); //true

-Symbol.iterator

这个比较特别,得到的也是symbol类型的值,是es6中提出用到对象中,被for…of遍历所用,下面将进行详细介绍。

由于这个值是标准规范提出,用于每个object中,所以应该是固定的值。

1
console.log(Symbol.iterator === Symbol.iterator); //true

用途

在我看来,symbol更多是应用于es6规范中,由于它的值唯一的特性,可以解决变量名,属性名冲突的问题,并切Symbol提出了一些属性和方法,用于过渡以及实现一些特殊的用途,比如对象的迭代器,instanceof的拓展等等。

  • 栗子。像我们项目中大量的使用常量定义字符串,尤其是react+redux的项目中,我觉得用Symbol就不错。
1
2
3
4
5
6
7
8
9
10
11
const GETLIST_SUCCESS = Symbol('get-list-success');

const getList = () => dispatch({
type: GETLIST_SUCCESS
}
)
const list = function(state = {}, action) {
switch(action.type):
case GETLIST_SUCCESS:
// code
}

我这里只是举一个例子,这种标识性的Symbol可以用的地方。大家可以不必关注redux。

  • 另外,Symbol值可以做为对象的key值,这样就能保证不会出现同名的属性名,防止对象属性被覆盖。下面我们将介绍Symbol作为属性名的写法。

作为对象的key

  • 对象[]方括号的形式
1
2
3
const obj = {}
const sym = Symbol();
obj[sym] = 'syj';
  • 对象内部定义
1
2
3
4
5
const sym = Symbol();

const obj = {
[sym]: 'syj'
}
  • 通过Object.defineProperty定义
1
2
3
4
5
6
7
8
const sym = Symbol();
const obj = Object.defineProperty({}, sym, {
enumerable: true, //可枚举
writable: true, //可赋值运算符改变
configurable: true, //可改变,可删除
value: 'syj'
}
)

注意,symbol作为属性名不能通过 . 的形式添加。

通过上述三种方式,我们就可以向对象添加key不会重复的symbol值了。意味着我们可以创建非字符串类型的属性名称,以防止使用常规手段来探查这些名称。

  • symbol类型的key的遍历

当我们用symbol设置了对象的key以后,他是不会被之前的for…in,Object.keys()遍历出来的,需要用Object.getOwnPropertySymbols()获取,得到一个所有这个对象中的symbol属性名的数组。

1
2
3
4
5
6
7
8
const sym1 = Symbol('1');
const sym2 = Symbol('2');
const obj = {
[sym1]: 'syj',
[sym2]: 'fy'
}
const ary = Object.getOwnPropertySymbols(obj);
console.log(ary); //[ Symbol(1), Symbol(2) ]

内置的Symbol值

  • 对象[]方括号的形式
1
2
3
const obj = {}
const sym = Symbol();
obj[sym] = 'syj';
  • 对象内部定义
1
2
3
4
5
const sym = Symbol();

const obj = {
[sym]: 'syj'
}
  • 通过Object.defineProperty定义
1
2
3
4
5
6
7
8
const sym = Symbol();
const obj = Object.defineProperty({}, sym, {
enumerable: true, //可枚举
writable: true, //可赋值运算符改变
configurable: true, //可改变,可删除
value: 'syj'
}
)

注意,symbol作为属性名不能通过

``` 的形式添加。
1
2
3
4
5
6

通过上述三种方式,我们就可以向对象添加key不会重复的symbol值了。意味着我们可以创建非字符串类型的属性名称,以防止使用常规手段来探查这些名称。

- symbol类型的key的遍历

>当我们用symbol设置了对象的key以后,他是不会被之前的for...in,Object.keys()遍历出来的,需要用Object.getOwnPropertySymbols()获取,得到一个所有这个对象中的symbol属性名的数组。

const sym1 = Symbol(‘1’);
const sym2 = Symbol(‘2’);
const obj = {
[sym1]: ‘syj’,
[sym2]: ‘fy’
}
const ary = Object.getOwnPropertySymbols(obj);
console.log(ary); //[ Symbol(1), Symbol(2) ]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

### 内置的Symbol值

>JavaScript内建的一些在 ECMAScript 5 之前没有暴露给开发者的符号,它们代表语言的内部行为。

- Symbol.iterator属性

我觉得是最重要的属性,它的提出使对象可以使用迭代器遍历,之前只有Array,String等,这种内置Symbol.iterator属性的可以使用迭代器。ECMAScript旨在使JS中使用一种方法,比如for...of就可以遍历序列数据,不需要关注它内部的数据结构。其实就是JS往C,JAVA语言靠拢的趋势吧。
为了避免此部分过于重,我们后面会专门研究迭代器和生成器。

- Symbol.hasInstance

>之前我们用instanceof的时候,比如```a instaceof A```其实就是调用的A对象中的Symbol.hasInstance属性,它指向一个内部方法,现在es6拓展出来,我们可以自己定义啦。

先看看下面的代码,猜想输出什么?

class MyClass{
static Symbol.hasInstance {
return num % 2 === 0
}

Symbol.hasInstance {
return num % 2 === 0
}
}
console.log(1 instanceof MyClass); // 序号(1)
console.log(2 instanceof MyClass); // 序号(2)
console.log(2 instanceof new MyClass()); // 序号(3)

const obj = {
Symbol.hasInstance {
return num % 2 === 0
}
}
console.log(1 instanceof obj);// 序号(4)


序号(1) MyClass类上有静态方法[Symbol.hasInstance], 1被当做参数传入function,返回结果false。 序号(2)同理,true。
序号(3) 后面是实例化的对象,通过原型链查找到原型上[Symbol.hasInstance],然后传入2执行,true。序号(4)是普通对象内部存在这个方法,执行返回false。
使用支付宝打赏
使用微信打赏

若你觉得我的文章对你有帮助,欢迎点击上方按钮对我打赏

扫描二维码,分享此文章