ES5 的对象属性名都是字符串,这容易形成属性名的冲突。好比,你使用了一个他人提供的对象,但又想为这个对象添加新的方法(mixin 模式),新方法的名字就有可能与现有方法产生冲突。若是有一种机制,保证每一个属性的名字都是独一无二的就行了,这样就从根本上防止属性名的冲突。这就是 ES6 引入Symbol的缘由。即Symbol是为了解决对象属性名冲突问题。es6
Symbol是es6引入的一种新的数据类型,表示独一无二的值。至此js共有7种数据类型,其中值类型为:undefined、null、布尔值(Boolean)、字符串(String)、数值(Number)、符号(Symbol)和引用类型:对象(Object)。函数
执行Symbol([description])函数能够生成一个与其余Symbol值互不相等的独一无二的Symbol值code
const sym = Symbol() // Symbol() const symWithNumber = Symbol(3.14) // Symbol(3.14) const symWithObject = Symbol({foo:'bar'}) // Symbol([object,object])
其中Symbol()函数接受一个可选的除Symbol值之外的值做为对该Symbol值的描述。这个描述值仅仅起到描述的做用,而不会对Symbol值自己产生任何影响。对象
const symWithSymbol = Symbol(sym) // TypeError: Cannot convert a Symbol value to a string const sym1 = Symbol('foo') const sym2 = Symbol('foo') sym1 === sym2 // false
Symbol()函数不是一个构造函数,前面不能加new关键字,不然会报错ip
new Symbol() // TypeError: Symbol is not a constructor
对象的属性名如今能够有两种类型,一种是原来就有的字符串,另外一种就是新增的 Symbol 类型。
当Symbol值做为对象的属性名时,要用方括号[],不然会被看成字符串处理作用域
let sym = Symbol(); // 第一种写法 let a = {}; a[sym] = 'Hello!'; // 第二种写法 let a = { [sym]: 'Hello!' }; // 第三种写法 let a = {}; Object.defineProperty(a, sym, { value: 'Hello!' }); // 以上写法都获得一样结果 a[sym] // "Hello!"
Symbol 做为属性名,遍历对象的时候,该属性不会出如今for...in、for...of循环中,也不会被Object.keys()、Object.getOwnPropertyNames()、JSON.stringify()返回。字符串
Object.getOwnPropertySymbols()方法能够获取全部 Symbol 属性名,get
另外一个新的 API,Reflect.ownKeys()方法能够返回全部类型的键名,包括常规键名和 Symbol 键名字符串处理
Symbol.for([key])与Symbol([description])都会生成Symbol值,它们的区别是,Symbol.for([key])会根据传入的key(字符串类型)在全局做用域中注册一个Symbol值,若是某个key从未被注册到全局做用域中,便会建立一个Symbol值并根据key注册到全局做用域中。若是该key已被注册,则会返回一个和第一次使用所建立的Symbol值等价的Symbol值。而Symbol([description])每一次调用都会返回不一样的Symbol值。string
const sym1 = Symbol.for('foo') const sym2 = Symbol.for('foo') sym1 === sym2 // true
既然能够根据字符串的key在全局环境中注册一个全局Symbol值,那么一样也能够到这些全局Symbol值对应的key值。
const sym = Symbol.for('foo') console.log(Symbol.keyFor(sym)) // foo