一、Symbol
的基本使用
在ES2015之前,对象的属性名都是字符串,而字符串有可能会重复,重复的话有可能会有冲突。
看一个例子,比如有3个js文件
// share.js=========
const cache = {}
// a.js=========
cache['foo'] = '123'
// b.js=========
cache['foo'] = Math.random()
console.log(catch)
现在我们大量使用第三方库,很多时候需要自己去扩展。如果出现属性重复怎么办呢?
ES2015之前的解决方案:约定。
给属性名添加特定前缀,比如说Vue内部也使用$和_作为内部方法或属性。
// share.js=========
const cache = {}
// a.js=========
cache['a_foo'] = '123'
// b.js=========
cache['b_foo'] = Math.random()
console.log(catch)
在ES2015中,新增了一种原始数据类型Symbol
—— 表示独一无二的值。
基本使用:
const s = Symbol()
console.log(s)// Symbol()
console.log(typeof s)// symbol
通过Symbol创建的值都是独一无二的,它永远不会重复:
console.log(Symbol() === Symbol())//false
console.log(Symbol('foo') === Symbol('foo'))//false
Symbol 可以传入一个字符串,作为这个值的描述文本,用于区分 :
console.log(Symbol('foo'))// Symbol(foo)
console.log(Symbol('baz'))// Symbol(baz)
从ES2015开始,对象就可以使用symbol类型的值作为属性名
新增对象的属性名可以是2种类型:string
、symbol
const obj = {
[Symbol()]:123,
[Symbol()]:456,
}
obj[Symbol()] = 789;
console.log(obj)//{[Symbol()]:123,[Symbol()]:456,[Symbol()]:789}
二、Symbol
目前最主要的作用——为对象添加独一无二的属性名
以前对私有成员都是靠约定,例如我们约定用下划线_开头就表示是私有成员,我们约定外界不允许访问对象中以下划线开头的成员。
现在,我们可以使用Symbol来创建私有成员的属性名
用Symbol来实现私有成员的属性名:
// a.js=========对外暴露一个对象person
const name = Symbol()
const person = {
[name]:'zce',
say(){
console.log(this[name])
}
}
// b.js=========
person.say() // zce
Symbol目前最主要的作用就是为对象添加独一无二的属性名
截止到ES2019,一共定义了7种数据类型:6种原始数据类型 (string、number、null、undefined、boolean、symbol) +一种复杂数据类型 object
未来还会添加一种原始数据类型BigInt,标准化过后就是8种数据类型了。
三、Symbol
的其他相关内容
如果需要在全局去复用一个Symbol,可以用全局变量,或者用Symbol类型提供的一个静态方法Symbol.for()
去实现
Symbol.for()
要求传入的参数是字符串string,如果传入的参数是其他类型,会被自动转为字符串string
const s1 = Symbol.for('foo')
const s2 = Symbol.for('foo')
console.log(s1 === s2)// true
console.log(Symbol.for('true') === Symbol.for(true)// true
Symbol提供了很多内置的symbol常量,用来作为内部方法的标识,这些标识符可以让自定义对象去实现一些js当中内置的接口
例如:
- Symbol.iterator
- Symbol.hasInstance
- Symbol.toStringTag
- …
const obj = {}
console.log(obj.toString()) // [object Object]
[object Object]
这个字符串称为对象的toString标签
如果想自定义对象的toString标签,可以在对象中添加一个特定的成员来标识
如果用字符串作为标识符,有可能会和内部的成员产生重复
ES2015 要求我们使用symbol值来实现这样的接口:
const obj = {
// toStringTag是内置的Symbol常量
[Symbol.toStringTag]:'XObject'
}
console.log(obj.toString()) // [object XObject]
使用Symbol
做作为属性名
使用传统的for in
循环、Object.keys()
、JSON.stringify()
都拿不到symbol 类型的属性
这个特性使得Symbol类型的属性特别适合用来作为对象的私有属性
const obj = {
[Symbol()]:'symbol value',
foo:'normal value'
}
// 那怎么获取symbol 类型的属性?
Object.getOwnPropertySymbols() // 使用方法类似于Object.keys()
console.log(Object.getOwnPropertySymbols(obj));// [ Symbol() ]
-
Object.keys()——获取对象中所有字符串类型的属性名
-
Object.getOwnPropertySymbols()——获取对象中所有symbol类型的属性名