ES6中引入一种新的原始数据类型symbol,表示独一无二的值,即使传递了一模一样的参数。
保证每个属性名都是独一无二的,从根本上防止属性名的冲突
原始数据类型Symbol
Symbol用法
const sl = Symbol()
const s2 = Symbol('symbol')
Symbol特点
- Symbol的值是独一无二的,每个Symbol值都是不同的
- Symbol值是通过Symbol函数生成的,Symbol函数可以接受一个字符串作为参数,表示对 Symbol 实例的描述
- Symbol函数如果传递一个对象作为参数,则会调用对象的toString方法将对象转换为字符串
- Symbol值不能与其他类型值进行运算,否则会报错
- Symbol值可以显式转为字符串或布尔值,但是不能转换为数字
- Symbol作为对象的属性名时需要用方括号[]包裹
- Symbol值作为对象属性名时,不能用点运算符。需要用:对象名[Symbol变量]的形式访问
- Symbol类型还可以定义一组常量,以保证这组常量的值都是不相等的
- Symbol作为对象属性名时,不会出现在for…in、for…of中,也不会被Object.keys()、Object.getOwnPropertyNames()、JSON.stringify()返回,但是可以通过Object.getOwnPropertySymbols()方法获取Symbol类型的属性名
// symbol是独一无二值
// 1、Symbol值通过Symbol函数生成
const s1 = Symbol()
const s2 = Symbol()
console.log(s1===s2) // flase
// 2、Symbol函数可以接受字符串作为参数
const s3 = Symbol('symbol')
const s4 = Symbol('symbol')
console.log(s3===s4) // flase
// 3、Symbol函数可以传递对象(数组)作为参数
const s5 = Symbol([1,2,3])
const s6 = Symbol({a: 1, b:2, c:3})
console.log(s5) // Symbol(1,2,3)
console.log(s6) // Symbol([object Object])
// 4、Symbol值不能与其他类型值进行运算
const s7 = Symbol('Hello')
console.log(s7 + ' world') // TypeError: can't convert symbol to string
// 5、Symbol值可以显式转为字符串和布尔值,但不能转数字
const s8 = Symbol('1')
String(s8) // Symbol(1)
s8.toString() // Symbol(1)
typeof s8 // "string"
Boolean(s8) //true
Number(s8) // TypeError: can't convert symbol to number
// 6. Symbol作为对象的属性名时需要用方括号[]包裹
// Symbol值作为对象属性名时,不能用点运算符。需要用:对象名[Symbol变量]的形式访问
const s9 = Symbol('obj')
const obj = { [s9]: 'hello world' }
console.log(obj.s9) // undefined 这种情况s9会被认为是字符串属性,所以获取不到 console.log(obj[s9]) // hello world
// 7. Symbol类型还可以定义一组常量,以保证这组常量的值都是不相等的
const msg = {}
msg.log = {
DEBUG: Symbol('debug'),
INFO: Symbol('info'),
WARN: Symbol('warn')
}
console.log(msg.log.DEBUG, 'debug message')
console.log(msg.log.INFO, 'info message')
// 8、Symbol作为对象属性名时,不会出现在for...in、for...of中,也不会被Object.keys() const obj = {}
const a = Symbol('a')
const b = Symbol('b')
obj[a] = 'Hello'
obj[b] = 'World'
obj.c = 'javascript'
Object.keys() // ['c']
Object.getOwnPropertySymbols(obj) // [Symbol(a), Symbol(b)]
Symbol使用场景
- 扩展其它人提供的对象
- 消除魔术字符串
- 为对象定义一些非私有的、但又希望只用于内部的方法
- 定义一组常量等等
问:怎么创建两个相同的Symbol值
有时我们希望传递相同的参数就能够创建出相同的Symbol值。其实symbol给我们提供了一个方法:Symbol.for(),接收一个字符串作为参数(可选),它会在全局中搜索有没有以改参数作为描述的Symbol值,如果有则返回,没有将该参数作为描述创建一个新的symbol值,并将其注册的全局环境供搜索,用Symbol方法创建的Symbol值是不会注册到全局的。
也就是说在使用Symbol.for()创建Symbol值时,首先会到全局环境中检测有没有创建,有就直接返回,没有再去创建新值,而Symbol则不管有没有都是创建新值。
另外:Symbol.for()在创建Symbol值时是登记在全局环境中的,不管有没有在全局环境运行
Symbol.for()
Symbol.for()与Symbol()这两种写法都能够生成新的 Symbol值。但它们的区别是,前者会被登记在全局环境中供搜索,而后者不会。Symbol.for()不会每次都去创建一个新的 Symbol 值,而是先检查全局环境中是否已经存在,如果不存在才会创建新值。比如,用Symbol.for(“symbol”)不管调用多少次,最后只有一个Symbol值,而如果换成Symbol(‘symbol’),那么调用多少次就会生成多少个新的Symbol值,比如调用100次那就是100个全新的Symbol值
const s1 = Symbol.for('symbol')
const s2 = Symbol.for('symbol')
console.log(s1 === s2) // true
const s3 = Symbol('symbol')
const s4 = Symbol('symbol')
console.log(s3 === s4) // false
// 无论在哪里调用,都会被注册登记到全局环境
function foo() {
return Symbol.for('symbol')
}
const x = foo()
const y = Symbol.for('symbol')
console.log(x === y); // true
Symbol.keyfor()
Symbol还提供了keyfor方法,此方法需与symbol.for方法配合使用,它的作用是用来获取被登记过的symbol值的key,就是创建symbol值的字符串。 keyfor方法接收一个Symbol类型的参数,用于返回该Symbol的key keyfor方法只能返回被登记过的Symbol值的key,也就是说只有通过Symbol.for方法创建的Symbol值的key才会被返回
const s1 = Symbol.for("symbol")
Symbol.keyFor(s1) // "symbol"
const s2 = Symbol("symbol")
Symbol.keyFor(s2) // undefined