Symbol类型
# Symbol
自ECMAScript2015起,symbol
成为了一种新的原生类型,就像number
和string
一样。symbol
类型的值是通过Symbol
构造函数创建的。可以传递参数作为唯一标识,只支持string
和number
类型的参数。
let sym1:symbol = Symbol()
let sym2:symbol = Symbol("key")
2
# Symbol的值是唯一的
const s1:symbol = Symbol(1)
const s2:symbol = Symbol(1)
// s1 === s2 false
2
3
# 如何让两个Symbol的值相等呢
Symbol.for 会全局找有没有注册这个key,如果有就直接拿来用,没有就会创建一个
console.log(Symbol.for('daodao') === Symbol.for('daodao')) //true
# 用作对象属性的键
let sym:symbol = Symbol()
let obj = {
[sym]:"value"
}
console.log(obj[sym]) // value
2
3
4
5
6
7
symbol定义的属性,是不能通过如下方式遍历拿到的
const symbol1:symbol = Symbol('666')
const symbol2:symbol = Symbol('777')
const obj1 = {
[symbol1]:'daodao',
[symbol2]:'miaomiao',
age:18,
sex:0
}
// 使用for in 遍历拿不到
for(const key in obj1) {
console.log(key) // age,sex
}
// 使用Object.keys遍历,拿不到
console.log(Object.keys(obj1)) // ['age','sex']
// getOwnPropertyNames, 拿不到
console.log(Object.getOwnPropertyNames(obj1)) // ['age','sex']
// JSON.stringfy,拿不到
console.log(JSON.stringify(obj1)) // {age:18,sex:0}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
那么如何拿到呢
// 用getOwnPropertySymbols拿到symbol属性,对象中有几个就会拿到几个
console.log(Object.getOwnPropertySymbols(obj1)) //[Symbol('666'),Symbol(777)]
// 用es6的Reflect拿到对象的所有属性
console.log(Reflect.ownKeys(obj1)) // [Symbol('666'),Symbol('777'),'age','sex']
2
3
4
5
# 生成器
生成器函数需要在function的后面加一个符号*,可以通过yield关键字来控制函数的执行流程,范湖一个Generator,是一种特殊的迭代器。
function* gen() {
yield Promise.resolve('喵') //同步异步都可以
yield '喵喵'
yield '喵喵喵'
yield '喵喵喵喵'
}
const man = gen()
console.log(man.next()) //{ value: Promise { '喵' }, done: false }
console.log(man.next()) //{ value: '喵喵', done: false }
console.log(man.next()) //{ value: '喵喵喵', done: false }
console.log(man.next()) //{ value: '喵喵喵喵', done: false }
console.log(man.next()) //{ value: undefined, done: true }
2
3
4
5
6
7
8
9
10
11
12
13
# 生成器提前结束 - return函数
return传值后这个生成器函数就会结束,之后调用next不会继续生成值了
function* foo(num) {
console.log("函数开始执行~")
const value1 = 100 * num
console.log("第一段代码:", value1)
const n = yield value1
const value2 = 200 * n
console.log("第二段代码:", value2)
const count = yield value2
console.log("函数执行结束~")
return "123"
}
const generator = foo(10)
console.log(generator.next())
// 第二段代码的执行, 使用了return
// 那么就意味着相当于在第一段代码的后面加上return, 就会提前终端生成器函数代码继续执行
console.log(generator.return(15)) //这里不会执行第二段代码了,因为提前终止了
console.log(generator.next())
console.log(generator.next())
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 迭代器
set是es6新增的,具有天然去重的特性,不过去重只能用于字符串和数字
let set:Set<number> = new Set([1,1,2,2,3,3]) //天然去重
console.log(set) // Set(3) { 1, 2, 3 }
2
map和数组类似,它支持对象作为键
let map:Map<any,any> = new Map()
let Arr = [1,2,3]
map.set(Arr, '刀刀')
console.log(map) //Map(1) { [ 1, 2, 3 ] => '刀刀' }
console.log(map.get(Arr)) //刀刀
2
3
4
5
6
它们都是伪数组,并不支持数组的方式遍历,那么如何遍历呢,这里就要用到迭代器,他们都有Symbol.iterator
方法
const each = (value:any) => {
let It:any = value[Symbol.iterator]()
let next:any = {done:false}
while(!next.done) {
next = It.next()
if(!next.done) {
console.log(next.value)
}
}
}
each(set) // 1 2 3
2
3
4
5
6
7
8
9
10
11
12
但是这样写未免也太麻烦了,其实迭代器是有语法糖的,就是for of,记住啦,for of是不能循环对象的因为对象没有iterator
// 迭代器的语法糖
// for of 对象不能用
for (let value of set) {
console.log(value) // 1 2 3
}
// 解构 底层原理也是去调用iterator
let [a,b,c] = [4,5,6]
2
3
4
5
6
7
8
怎样才能让对象支持for of呢,我们可以给对象添加一个iterator
const obj = {
max: 5,
current: 0,
[Symbol.iterator]() {
return {
max: this.max,
current: this.current,
next() {
if (this.current == this.max) {
return {
value: undefined,
done: true
}
} else {
return {
value: this.current++,
done: false
}
}
}
}
}
}
console.log([...obj]) [0,1,2,3,4]
for (let val of obj) {
console.log(val); // 1 2 3 4 5
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
以下为这些symbols的列表
Symbol.hasInstance
会被instanceof运算符调用。构造器对象用来识别一个对象是否是其实例。
Symbol.isConcatSpreadable
布尔值,表示当在一个对象上调用Array.prototype.concat时,这个对象的数组元素是否可展开。
Symbol.iterator
方法,被for-of语句调用。返回对象的默认迭代器。
Symbol.match
方法,被String.prototype.match调用。正则表达式用来匹配字符串。
Symbol.replace
方法,被String.prototype.replace调用。正则表达式用来替换字符串中匹配的子串。
Symbol.search
方法,被String.prototype.search调用。正则表达式返回被匹配部分在字符串中的索引。
Symbol.species
函数值,为一个构造函数。用来创建派生对象。
Symbol.split
方法,被String.prototype.split调用。正则表达式来用分割字符串。
Symbol.toPrimitive
方法,被ToPrimitive抽象操作调用。把对象转换为相应的原始值。
Symbol.toStringTag
方法,被内置方法Object.prototype.toString调用。返回创建对象时默认的字符串描述。
Symbol.unscopables
对象,它自己拥有的属性会被with作用域排除在外。