首页 > es6 Symbol

es6 Symbol

看阮一峰的教程他说Symbol对于一个对象由多个模块构成的情况非常有用,能防止某一个键被不小心改写或覆盖
这个应该怎么理解?
我试着写了下,好像感受不以Synmbol这东西是唯一的!!
这个唯一要怎么理解?

var x = Symbol('show');
var y = Symbol('hello');

var a = {
    [x] : function(){
        console.log('xxx');
    },
    [y] : function(){
        console.log('yyy');
    },
    x : function(){
        console.log('ssssss')    
    }
}

a.x() //ssssss
a[x]();//xxx
a[y]();//yyy

以前属性名只能是数字或者字符串,很容易发生覆盖,
但是如果用Symbol,完全可以这样玩

var a = {
    [Symbol()] : function(){
        console.log('xxx');
    },
    [Symbol()] : function(){
        console.log('yyy');
    }
}

因为Sysbol() !== Symbol()始终为true,所以两个Symbol()不可能相等,这就避免了覆盖


不是Symbol()返回唯一的东西。是Symbol返回的东西是唯一的。

而且你也知道,一个对象不能有相同的key,可是下面的对象是合法的。

{
    [Symbol()]: 1,
    [Symbol()]: 1, // Symbol() !== Symbol()
    [Symbol('x')]: 1, 
    [Symbol('y')]: 1, // Symbol('x') !== Symbol('y')
    [Symbol('x')]: 1, // Symbol('x') !== Symbol('x')
}

Symbol返回的东西是唯一的

而且楼上的例子也很清楚Symbol() !== Symbol(),每次Symbol()返回的都是不一样的。

下面说说这个唯一怎么理解,为什么要用这个Symbol。

部署接口

你是js语法标准的制定者。现在你要为Array对象添加一个方法one,用来输出这个数组中第一个元素。

const array = [1, 2, 3];
console.log(array.one()); // => 1

但是现在网上有大量的js代码,很多都对Array进行了拓展。为了保证现有的代码和你定的新方法名称不产生冲突,你会怎么办呢?毕竟你选的任何一个方法名都有可能和大家重复。

于是Symbol登场了。Symbol()每次返回的东西是唯一的,不和其他类型相同,所以你可以尽情地添加方法了。

Symbol.one = Symbol();
Array.prototype[Symbol.one] = function() {
    return this[0];
}
Array.prototype.one = function() {
    return 'taken';
}

const array = [1, 2, 3];
console.log(array[Symbol.one]()); // => 1
console.log(array.one()); // => 1

私有

你现在有了一个模块

function getModule() {
  return {
    _data: 'world',
    hello(){
        console.log(this._data);
    }
  }
}

const mod = getModule();
mod.hello(); // => world

但是使用的人很容易篡改

const mod = getModule();
mod._data = 'bug'
mod.hello(); // => bug

当别人使用你的模块的时候并不想让他们碰_data,因为你认为这个是私有的。

解决办法呢?万能的闭包。

function getModule(module) {
  let _data = 'world';
  return (function(){
    return {
      hello(){
        console.log(_data)
      }
    }
  })()
}
const mod = getModule();
mod._data = 'bug'
mod.hello(); // => world

解决了私有的问题,但是出现了另一个问题。
调试的时候,根本无法从模块的外面知道这个模块到底有什么私有的数据。比如别人调试到你的程序的时候。

>utils.inspect(mod, {showHidden: true});
'{ hello: { \[Function: hello\] \[length\]: 0, \[name\]: \'hello\' } }'

但是在Node里,util.inspect无法看到闭包。

当然,如果在Chrome的devtool下,console.log()这个对象的时候是可以看function scope的。

这个时候最适合Symbol了。

const data = Symbol('data');
function getModule() {
  return {
    [data]: 'world',
    hello(){
      console.log(this[data])
    }
  }
}

这样,你在返回的对象上不管怎么赋值,都不会出现覆盖。可以被其他人随便封装。

const m = getModule();
m.data = 'bug';
m.hello(); // => world
m[Symbol('data')] = 'bug';
m.hello(); // => world

而且还可以inspect看内部的数据。

【热门文章】
【热门文章】