Symbol

2021/12/4

# 介绍

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

# 概念

概念表

名字 作用
全局注册表 全局的一个键值对表
描述符 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
  • 最佳实践:再全局注册表中加上前缀,减少全局污染
const hdy = Symbol.for('hdy.name');
const js = Symbol.for('hdy.skill');
console.log(Symbol.for('hdy.name')); // Symbol(hdy.name)
1
2
3

# keyFor

  • 作用:拿到全局注册表的Symbol的键
  • 调用:Symbol.keyFor(syb)
  • 入参:Symbol
const js = Symbol.for('hdy.skill');
console.log(Symbol.keyFor(js)); // hdy.skill
1
2

# 属性

# description

  • 原型属性:Symbol.prototype.description
  • 类型:String
  • 值:构造时的入参,和Symbol.keyFor()返回值一样
const s = Symbol('hdy');
console.log(s.description === 'hdy'); // true
1
2
  • 其他类型会被转换成String
const a = Symbol(true);
console.log(typeof a.description); // string
1
2
  • 和Symbol.keyFor()返回值一样
const js = Symbol.for('hdy.skill');
console.log(js.description === Symbol.keyFor(js)); // true
1
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

# isConcatSpreadable

  • 作用:调用数组concat连接时是否展开
  • 类型:Boolean
  • 默认:true

# 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

# asyncIterator

  • 作用:异步迭代器
  • 调用:for await (...of...) {}
  • 难点:每一层await都会包装一次Promise,影响执行顺序

# match

  • 作用:以正则的规则去匹配调用者
  • 调用:str.match(RegExp)
  • 值:Function(String.prototype.match调用的方法)/Boolean (判断是否用正则匹配,false就转换字符串匹配)

特殊

configurable value
configurable false
enumerable false
writable false

# matchAll

  • 作用:同match
  • 调用:String.prototype.matchAll()

# replace

  • 作用:同match
  • 调用:String.prototype.replace()

  • 作用:同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

# 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
  • 修改后:本类的实例 => 的衍生对象 => 的构造类,做出了修改

 
 
 



 
 


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

# 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

# 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

# unscopables

  • 作用:使用with更换作用域时时排除的属性名称
  • tip:《红宝书》不建议使用with,代码不易读不易维护
上次更新: 9/17/2024