# 介绍
Symbol
- 作用:作为对象属性的标识符
- 内置:静态属性、静态方法
- 特点:不支持new创建、Symbol()返回的Symbol值是唯一的
- 入参:String/其他类型会被转成字符串
const s1 = Symbol(1); const s2 = Symbol(1); console.log(s1 == 1); // false console.log(s1 === s2); // false console.log(typeof s1); // symbol
复制成功
1
2
3
4
5
6
2
3
4
5
6
# 概念
概念表
名字 | 作用 | 例 |
---|---|---|
全局注册表 | 全局的一个键值对表 | |
描述符 | Symbol()或Symbol.for()时的入参 | 'hdy.name' |
键 | 定义时的描述符 | hdy.name |
值 | Symbol.for()的返回值 | Symbol(hdy.skill) |
# 方法
# for
- 作用:在
全局注册表中
注册或读取Symbol - 调用:Symbol.for(str)
- 返回:注册好的Symbol
- tip:查找
全局注册表
有没有相关描述的Symbol,有则返回,无则在全局注册表中创建
const s1 = Symbol.for('全局标记1'); const s2 = Symbol.for('全局标记1'); console.log(s1); // Symbol(全局标记1) console.log(s1 === s2); // true
复制成功
1
2
3
4
2
3
4
- 最佳实践:再全局注册表中加上前缀,减少全局污染
const hdy = Symbol.for('hdy.name'); const js = Symbol.for('hdy.skill'); console.log(Symbol.for('hdy.name')); // Symbol(hdy.name)
复制成功
1
2
3
2
3
# keyFor
- 作用:拿到全局注册表的Symbol的键
- 调用:Symbol.keyFor(syb)
- 入参:Symbol
const js = Symbol.for('hdy.skill'); console.log(Symbol.keyFor(js)); // hdy.skill
复制成功
1
2
2
# 属性
# description
- 原型属性:Symbol.prototype.description
- 类型:String
- 值:构造时的入参,和Symbol.keyFor()返回值一样
const s = Symbol('hdy'); console.log(s.description === 'hdy'); // true
复制成功
1
2
2
- 其他类型会被转换成String
const a = Symbol(true); console.log(typeof a.description); // string
复制成功
1
2
2
- 和Symbol.keyFor()返回值一样
const js = Symbol.for('hdy.skill'); console.log(js.description === Symbol.keyFor(js)); // true
复制成功
1
2
2
# hasInstance
- 作用:重写instanceof判断方式
- 调用:obj instanceof CLASS
// 改写 instanceof 默认判断 class A { static [Symbol.hasInstance]() { return true; } } const a = ''; const b = 1; const c = false; console.log(a instanceof A); // true console.log(b instanceof A); // true console.log(c instanceof A); // true
复制成功
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
# isConcatSpreadable
- 作用:调用数组concat连接时是否展开
- 类型:Boolean
- 默认:true
使用
拼接类数组对象
nodelist拼接
- Array.prototype.concat()默认展开了一层数组再进行拼接的
- 更改了[Symbol.isConcatSpreadable]后,可以自定义这个行为
const a = [1, 2]; const b = [3, 4, 5]; // 默认展开再做连接 console.log(a.concat(b)); // [1, 2, 3, 4, 5] // 更改默认属性 b[Symbol.isConcatSpreadable] = false; const c = a.concat(b); console.log(c); // [ 1, 2, [ 3, 4, 5, [Symbol(Symbol.isConcatSpreadable)]: false ] ] for (let i of c[2]) { console.log(i); // 3 4 5 }
复制成功
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
# iterator
Symbol.iterator
- 作用:获取对象迭代器的函数
- 调用:for...of
- 返回:Iterator
特殊
configurable | value |
---|---|
configurable | false |
enumerable | false |
writable | false |
- 对象默认不可以被for...of 迭代
const obj = { name: 'hdy', age: 18, } // TypeError: obj is not iterable // for (let value of obj) { } // 增加迭代器 obj[Symbol.iterator] = function* () { const keys = Object.keys(this); for(let key of keys) { yield obj[key]; } } for (let value of obj) { console.log(value); // hdy 18 }
复制成功
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# asyncIterator
- 作用:异步迭代器
- 调用:for await (...of...) {}
- 难点:每一层await都会包装一次Promise,影响执行顺序
使用
执行顺序
// 定义可异步迭代对象 const obj = {}; obj[Symbol.asyncIterator] = async function*() { yield 'hdy'; yield '18岁'; yield '爱读书'; }; // 后面是立即执行函数,这里必须有分号 // 异步迭代 (async () => { for await (const i of obj) { console.log(i); // hdy 18岁 爱读书 } })()
复制成功
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
# match
- 作用:以正则的规则去匹配调用者
- 调用:str.match(RegExp)
- 值:Function(String.prototype.match调用的方法)/Boolean (判断是否用正则匹配,false就转换字符串匹配)
特殊
configurable | value |
---|---|
configurable | false |
enumerable | false |
writable | false |
Boolean作用
Function作用
- 原生
- String.prototype的startsWith/endsWith/includes不允许用正则,会检测是否有此方法
const str = '123'; const reg = /1/; console.log(str.startsWith(reg)); // error
复制成功
1
2
3
2
3
- 修改
const str = '123'; const reg = /1/; reg[Symbol.match] = false; // 检测Symbol.match变为false,就用字符串匹配 console.log(str.startsWith(reg)); // false 开头匹配不到'/1/'这个字段
复制成功
1
2
3
4
2
3
4
# matchAll
- 作用:同match
- 调用:String.prototype.matchAll()
# replace
- 作用:同match
- 调用:String.prototype.replace()
# search
- 作用:同match
- 调用:String.prototype.search()
# split
- 作用:同match
- 调用:String.prototype.split(reg)
const s = '1$2$3'; const reg = /\$/; console.log(s.split(reg)); // [ '1', '2', '3' ] // 修改默认做法 reg[Symbol.split] = (str) => ['嘿', '嘿嘿', '嘿嘿嘿']; console.log(s.split(reg)); // [ '嘿', '嘿嘿', '嘿嘿嘿' ]
复制成功
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
# species
- 作用:决定此对象衍生出来的对象的构造类
- 原生构造类
class MyArray extends Array {} const a = new MyArray(1, 2, 3); const mapped = a.map(x => x); console.log(mapped instanceof MyArray); // true console.log(mapped instanceof Array); // true
复制成功
1
2
3
4
5
6
2
3
4
5
6
- 修改后:本类的实例 => 的衍生对象 => 的构造类,做出了修改
class MyArray extends Array { static get[Symbol.species]() { return Array; // 衍生对象的构造函数就是Array构造,和MyArray没有关系 } } const a = new MyArray(1, 2, 3); const mapped = a.map(x => x); console.log(mapped instanceof MyArray); // false console.log(mapped instanceof Array); // true
复制成功
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
# toPrimitive
- 作用:默认转化类型时使用
- 调用:+str/
${obj.str}
/!str/等 - 入参hint:'number'|'string'| 'default'
const obj = {}; console.log(+str + 3); // NaN obj[Symbol.toPrimitive] = (hint) => 1000; console.log(+str + 3); // 1003
复制成功
1
2
3
4
5
2
3
4
5
# toStringTag
- 作用:Object.prototype.toString()会拿到此方法返回值做拼接
class A {} const a = new A(); console.log(a.toString()); // [Object object] Object.defineProperty(A.prototype, Symbol.toStringTag, { get() { return 'A'; } }) console.log(a.toString()); // [Object A]
复制成功
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
# unscopables
- 作用:使用with更换作用域时时排除的属性名称
- tip:《红宝书》不建议使用with,代码不易读不易维护
v1.4.16