ES6新增数据类型:Symbol类型

什么是Symbol类型

作为一个对象,如果这个对象是一个全局变量,在每一个模块中,我们都要使用这个对象,这个时候就会出现一个问题,我如何保证我的对象的属性是唯一的?

//全局对象obj
var obj = {
    name: 'mapbar_front',
    age: 27
}
//在另一个文件a.js中
obj.name = 'mapbar';
//在新的b.js文件中
console.log(obj.name);

我们的需求是,可能我要给一个全局对象添加一个属性,用来记录某个值,但是你慢慢会发现,很有可能我们会造成我们的键名的覆盖,也就是上面发生的事情。

ES6针对JavaScript语法中的这个缺点,提出了一种新的数据类型:Symbol数据类型。它的值是使用Symbol()函数得到的,返回一个在全局作用域中的唯一的、确定的一个值。

var s1 = Symbol();
var s2 = Symbol();
console.log(s1 === s2);
//这个时候的s1和s2是不相等的。
console.log(typeof s1);//Symbol

Symbol数据类型有这么几个特征

  • 可以添加一个字符串,作为一个Symbol的标识
var s1 = Symbol('mapbar_front');
var s2 = Symbol('mapbar_front');
console.log(s1 === s2);// false
s1.toString();// "Symbol('mapbar_front')"
  • Symbol类型数据可以显式的转化为布尔值、字符串。但是不能转为数值,会报错。
var s1 = Symbol();
Boolean(s1);//true
if(s1){
    //code
}
Number(s1);//报错 TypeError
  • Symbol类型的数据不能参与运算,会报错。
`我是${Symbol()}`;//报错,Symbol不会自动转为string类型
var a = Symbol() + 1;// 报错

Symbol作为对象的属性

Symbol值作为一个对象的属性,一般使用一个定义好的变量来表示,要不你不太容易去访问。

var s1 = Symbol();
var obj = {
    [s1]: 'mapbar_front'
}
console.log(obj[s1]);//mapbar_front


var obj2 = {
    Symbol(): 'mapbar_front'
}
obj2[Symbol()];//访问不到mapbar_front,这是由Symbol的唯一性所确认的。

Symbol数据的一大应用,就是解除魔法字符串。

function getArea(type, options) {
 var area = 0;
    switch (type) {
        case 'Triangle':
            area = 0.5 * options.width * options.height;
            break;
    }

    return area;
}
getArea('Triangle',{width: 200, height: 200});

上面的代码,形成了非常强烈的 “Triangle” 耦合。
可以使用下面的方式进行改进:

var type = {
  triangle: 'Triangle'
}
function getArea(shape, options) {
    var area = 0;
    switch (shape) {
        case type.triangle:
            area = 0.5 * options.width * options.height;
            break;
    }

    return area;
}
getArea(type.triangle,{width: 200, height: 200});

上面的一段代码,使用了变量的方式,消除了魔法字符串。大大降低了耦合度,你仅仅使用一个变量的方式实现了相同的功能。

甚至你在这里,你可以使用Symbol类型代替’Triangle’字符串。

Symbol作为属性名的遍历

  • for in一般用来遍历对象,但是无法遍历出属性名为Symbol值的对象。
    (for of 的方式也无法遍历出属性名为Symbol类型的数据)
var obj = {
    [Symbol()]: 'mapbar',
    a: 123
}
for(var i in obj){
    console.log(i);
}
//只循环遍历到 a。

一般而言,我们使用Object.getOwnPropertyNames()遍历Symbol类型的属性。这种方式无法遍历出普通类型的的属性名。

var obj = {
    a: 1,
    [Symbol()]: 123,
    [Symbol('ff')]: 234,
}
var list = Object.getOwnPropertySymbols(obj);
console.log(list);//['Symbol()', 'Symbol(ff)']

Symbol.for()、Symbol.keyFor()

有时候,你想使用同一个Symbol的值,Symbol.for就能满足你的需求。

Symbol.for(‘str’),它会在全局区域查找有没有Symbol(‘str’)的值,如果找到了,直接返回这个引用,如果没有找到,它自己就实例化一个Symbol值。

var s1 = Symbol.for('foo');
var s2 = Symbol.for('foo');
console.log(s1 === s2);// true

关于Symbol.keyFor(),看下面这个示例:

var s1 = Symbol.for('foo');
var str = Symbol.keyFor(s1);
console.log(str);// 'foo'

但是Symbol.keyFor只能捕捉使用Symbol.for()创建的Symbol实例,因为它会被注册到全局中,便于查找,普通的Symbol实例是不会被捕捉到的。

var s2 = Symbol('ffff');
console.log(Symbol.keyFor(s2));

内置的Symbol值

内置的Symbol值是在进行一些内置语言层面的操作的时候,会触发相应的方法。

  • Symbol.hasInstance
    表示在使用 instanceof操作符的时候,调用的内部方法。
class Even {
    static [Symbol.hasInstance](obj){
        return obj % 2 === 0
    }
}
console.log(1 instanceof Even);// false
console.log(2 instanceof Even);//true
  • Symbol.isConcatSpreadable
    表示调用数组的concat方法的时候,数组是否展开的时候调用的方法。
  • Symbol.species
    表示创建衍生对象的时候,调用的构造函数。
  • Symbol.match
  • Symbol.replace
  • Symbol.search
  • Symbol.split
  • Symbol.iterator
  • Symbol.toPrimitive
  • Symbol.toStringTag
  • Symbol.unscopables

猜你喜欢

转载自blog.csdn.net/mapbar_front/article/details/80926948