先简单说说什么是Symbol
- Symbol是ES6新增的基础数据类型,它的特色就是独一无二的,如同UUID同样;
- Symbol是函数,经过调用Symbol函数来建立Symbol数据;
- Symbol仍是内置对象,提供一系列函数well-known Symbol方法来改变JS语言的内部行为;
Symbol的特性与使用
示例:建立Symbol数据
- Symbol没有字面量的建立方式,也不能以
new Symbol()
构造函数的方式建立,只能经过调用Symbol([description])
函数,或者Symbol.for()
来建立。
new Symbol()
let symbol1 = Symbol()
let localSymbol Symbol('desc1')
let globalSymbol = Symbol.for('desc1')
console.log(localSymbol === globalSymbol)
复制代码
特性:Symbol老是惟一的
- 数据老是独一无二的,不只在函数、模块甚至在window顶层做用域中都是惟一的
let f1 = Symbol('flag')
let f2 = Symbol('flag')
console.log(f1,f2)
console.log(f1 === f2)
console.log(f1 === 'flag')
let lock = Symbol.for('flag')
let lockFlag = Symbol.for('flag')
console.log(lock === lockFlag)
console.log(f1 === lock)
console.log(Symbol.keyFor('flag'))
console.log(Symbol.keyFor('test'))
复制代码
示例:使用Symbol来定义常量
- 既然Symbol的特性是惟一标志,咱们能够用Symbol来作常量。
- 之前咱们定义常量是这样婶的:
const FRUIT = {
APPLE: 'APPLE',
BANANA: 'BANANA',
STRAWBERRY: 'STRAWBERRY'
}
console.log(FRUIT.APPLE)
const FRUIT = {
APPLE: 'APPLE',
BANANA: 'BANANA',
STRAWBERRY: 'STRAWBERRY',
PINEAPPLE: 'APPLE'
}
const FRUIT = {
APPLE: Symbol(),
BANANA: Symbol(),
STRAWBERRY: Symbol()
}
function translate(FRUIT_TYPE){
switch (FRUIT_TYPE) {
case FRUIT.APPLE:
console.log('苹果')
break;
case FRUIT.BANANA:
console.log('香蕉')
break;
case FRUIT.STRAWBERRY:
console.log('草莓')
break;
default:
console.log('未匹配')
break;
}
}
translate(FRUIT.APPLE)
复制代码
示例:使用Symbol来定义人名
- 好比一个班级里面,想经过人名来做为惟一标识,但人名又没办法避免重复,经过Symbol来实现
const grade = {
[Symbol('Lily')]: {
address: 'shenzhen',
tel: '186******78'
},
[Symbol('Annie')]: {
address: 'guangzhou',
tel: '183******12'
},
[Symbol('Lily')]: {
address: 'beijing',
tel: '172******10'
},
}
复制代码
特性:Symbol的类型判断和类型转换
- 和String类型同样,Symbol类型能够经过
typeof
操做符进行类型判断
let symbol = Symbol()
console.log(typeof Symbol)
复制代码
- 但和String类型不同的是,Symbol不会进行隐式的自动类型转换,因此不能直接进行字符串拼接运算和算术运算。但能够人为的进行显式类型转换,好比转成String、Boolean、Number、Object
let symbolUUID = Symbol('uuid')
console.log(symbolUUID + '测试')
console.log(symbolUUID + 1)
console.log(symbolUUID ? '真' : '假')
console.log(String(symbolUUID) + '测试')
复制代码
特性:Symbol可做为对象的属性key名
- 根据规范,Symbol类型能够做为数据单独存在,也能够做为对象的属性key名。而且,对象的属性key只能是字符串类型或者Symbol类型,没有别的数据类型能够做为属性key,Boolean不行,Number也不行。
- 但值得注意的是,须要以
{[SymbolKey]: value}
数组括弧的方式来挂载。
let desc = Symbol('desc')
let person = {
name: 'huilin',
sex: '男',
[desc]: '职位:前端工程师'
}
console.log(person)
复制代码
console.log(JSON.stringify(person))
for(key in person){
console.log(key)
}
console.log(Object.keys(person))
console.log(Object.getOwnPropertyNames(person))
console.log(Object.getOwnPropertySymbol(person))
console.log(Reflect.ownKeys(person))
复制代码
示例:经过Symbol模拟对象的私有属性或者私有方法
const id = Symbol()
class User {
constructor(idVal, name, age){
this[id] = idVal
this.name = name
this.age = age
}
checkId(id){
return this[id] === id
}
}
let u = new User('001', 'Jay', 40)
console.log(u.name, u.age, u[id])
console.log(u.checkId('001'))
console.log(u.checkId('002'))
复制代码
示例:利用Symbol进行数据归集和整合
- 拿张鑫旭大佬打听小美眉的例子来看,一般状况下两个对象合并,key相同则会覆盖:
let info1 = {
name: '小雪',
age: 24,
job: '前端工程师',
desc: '喜欢看电影,已经有交往对象'
}
let info2 = {
desc: '喜欢小狗,住在南山区,上下班坐公交车'
}
console.log(Object.assgin(info1,info2))
复制代码
- 那改为用Symbol做为属性key名会怎样呢?Symbol不会进行覆盖的
let info1 = {
name: '小雪',
age: 24,
job: '前端工程师',
[Symbol('desc')]: '喜欢看电影,已经有交往对象'
}
let info2 = {
[Symbol('desc')]: '喜欢小狗,住在南山区,上下班坐公交车'
}
console.log(Object.assgin(info1,info2))
复制代码
- 可见,Symbol更关注的是value值,而不是key名。能够思考得出,Symbol的特性就是方便对数据进行归集和整合。
- 拿现实中的例子来讲吧,微信文章的点赞墙,数据值都是点赞,但记录不会被覆盖,用户的头像都会罗列出来;再好比签到簿,数据值是时间,颇有多是扎堆签到时间同样,但也不会被覆盖,而是把记录罗列进来。
- 再回到JavaScript语法层面,可能你们会以为,名字冲突这种事情,几率很低吧?有必要专门新增一个Symbol嘛?可是你想啊,ES6的Module,导入导出是能够起别名的;还有ES6的解构,能够直接获取对象的属性名到当前环境;这样你还以为名字冲突的几率低吗?
- 因此Symbol经过归集和整合的特性,针对基础框架版本升级时,便于同名的方法或者变量向下兼容。
系统Symbol
- 除了本身建立Symbol标记以外,ES6还提供了一系列内置的well-know(众所周知)的Symbol标记,用于改变JavaScript底层API的行为
API |
desc |
Symbol.hasInstance |
当调用instanceof运算符判断实例时,会调用这个方法 |
Symbol.isConcatSpreadable |
当调用Array.prototype.concat()时,判断是否展开 |
Symbol.unscopables |
对象指定使用with关键字时,哪些属性会被with环境排除 |
Symbol.match |
当执行str.match(obj)时,若是该属性存在会调用它,并返回方法的返回值 |
Symbol.replace |
当执行str.replace(obj)时调用,并返回方法的返回值 |
Symbol.search |
当执行str.search(obj)时调用,并返回方法的返回值 |
Symbol.split |
当执行str.split(obj)时调用,并返回方法的返回值 |
Symbol.iterator |
当对象进行for...of循环时,调用Symbol.iterator方法,返回该对象默认遍历器 |
Symbol.toPrimitive |
当对象被转换为原始数据类型时调用,返回该对象对应的原始数据类型 |
Symbol.toStringTag |
在该对象调用toString方法时调用,返回方法的返回值 |
Symbol.species |
建立衍生对象时使用该属性 |
参考