文章目录
一、Symbol是什么?
- Symbol 是 ES6 新推出的一种基本类型,它的值是唯一的.
- 它可以接受一个字符串作为参数,带有相同参数的两个Symbol值不相等.
- 参数只是表示Symbol值的描述,主要用于程序调试时的跟踪.
- 当然也可以不传参,也可以通过typeof来判断是否为Symbol类型.
二、基本用法
- 如果你对Symbol有一定的了解,可直接看第三部分.
1.Symbol值的基本获取
- 任意两个symbol的值是不相等的
const s1 = Symbol();
const s2 = Symbol();
console.log(s1 === s2); // false
- 可以写参数,但仅仅用于描述.
const s1 = Symbol('test');
const str = 'test';
const s2 = Symbol('test');
console.log(s1 === str); // false
console.log(s1 === s2); // false
console.log(s1); // Symbol(debug)
- Symbol也属于基本类型,可以使用typeof检测
const s1 = Symbol('test');
console.log(typeof s1); // symbol
2.一些使用
- 作为对象的属性使用,这也是最多的用法,可是一般对象属性,用这个属实没啥意思.
let sym1 = Symbol('test');
let obj={name: 'lin', [sym1]: 'foo'};
console.log(obj);
- 获取Symbol作为属性值时的属性.
let s1 = Symbol('foo'),
s2 = Symbol('bar');
let o={
[s1]:'foo val',
[s2]:'foo bar',
baz:'baz val',
qux:'quxval'
}
console.log(Object.getOwnPropertySymbols(o));
// [Symbol(foo), Symbol(bar)]
console.log(Object.getOwnPropertyDescriptors(o));
// {baz: {…}, qux: {…}, Symbol(foo): {…}, Symbol(bar): {…}}
3. 使用全局符号注册
- 如果运行时不同部分需要和重用符号实例,可以用一个字符串作为键,在全局符号注册表中创建并重用符号.
- 使用Symbol.for()即可.
let id = Symbol.for("test"); //获取desc为test的symbol 无则创建
let id1 = Symbol.for("test"); //获取desc为test的symbol 有则获取
console.log(id == id1); //true
- 在全局注册表中定义符号和Symbol()中定义的符号并不相等.
let id = Symbol.for("test"); //全局注册
let id1 = Symbol('test');
console.log(id==id1); // false
- 使用keyFor() 查询全局注册表.
let a1 = Symbol.for("a");
Symbol.keyFor(a1); // "a"
let a2 = Symbol("a");
Symbol.keyFor(a2); // undefined
三、常用内置符号
- ES6中引入一些常用内置符号,用于暴露语言内部的行为.
- 这些内置符号的重要作用就是重新定义他们,从而改变原生结构方法.
- 如for-of的循环会在相关对象上用Symbol.iterator属性,我们就可以重新定义它.
1 认识Symbol.hasInstance
- 可以判断某对象是否为某构造器的实例。
- 因此可以用它自定义 instanceof 操作符在某个类上的行为.
class Foo{}
let f = new Foo();
console.log(f instanceof Foo); // true
- 在 ES6中 instanceof 会调用Symbol.hasInstance来确定关系.
class Foo{}
let f = new Foo();
console.log(Foo[Symbol.hasInstance](f)); // true
- 该属性定义在Function的原型上,故任何的类和函数都可调用.
- 因为instanceof会在原型链上寻找这个属性定义,因此我们可以重构它.
class Bar{}
// 在Baz 中重构,该静态方法
class Baz extends Bar{
static [Symbol.hasInstance](){
return false;
}
}
let b = new Baz();
console.log(Bar[Symbol.hasInstance](b)); // true
console.log(b instanceof Bar); // true
// 此时在判断,统一返回false
console.log(b instanceof Baz); // false
console.log(Baz [Symbol.hasInstance](b)); // false
2 重构数组concat()方法
- Symbol.isConcatSpreadable属性主要控制数组concat()的合并方式.
- 返回值为true时,则Array.prototype.concat()将打平数组.
let arr1=['foo'],arr2=['bar'];
console.log(arr1.concat(arr2)); // ['foo', 'bar']
- 返回值为false时,则Array.prototype.concat()会将整个对象追加到数组末尾
let arr1=['foo'],arr2=['bar'];
// 设置为false,则将数组直接添加到最后,而不会平铺
arr2[Symbol.isConcatSpreadable]= false;
console.log(arr1.concat(arr2)); // ['foo', Array(1)]
3 重构正则match() 方法
- match()主要是用正则表达式匹配字符串
- String.prototype.match()会使用以Symbol.match为键的函数来对正则表达式求值.
console.log(RegExp.prototype[Symbol.match]);
// ƒ [Symbol.match]() { [native code] }
console.log('foobar'.match(/bar/));
// ['bar', index: 3, input: 'foobar', groups: undefined]
- 给match() 传入非正则时会被转化为哦RegExp对象.
- 我们可以重新定义函数,让方法直接使用参数.
class StringMatcher{
// 接收外部传递的参数
constructor(str){
this.str = str;
}
// 重新定义math的匹配规则
static [Symbol.match](target){
return target.incluedes(this.str)
}
}
console.log('fooBar'.match(new StringMatcher('foo')));
//true ['o', index: 1, input: 'fooBar', groups: undefined]
console.log('barbaz'.match(new StringMatcher('foo')));
//false ['b', index: 0, input: 'barbaz', groups: undefined]
正则的replace() 底层也是调用 Symbol.replace().
正则的search() 底层也是调用 Symbol.search().
总结
- Symbol在JS中,应被用作一种对象的归类方法,或着对象的标记方法。在共同协作或多库运行时,能够有效的减少代码的误操作几率。
- 在ES6中很多api的底层已经在使用Symbol进行定义.
- 凡是能用字符串和数字作为属性的地方都可以使用Symbol.
本文介绍了JavaScript中的Symbol类型,包括其唯一性、基本用法,如作为对象属性使用,以及如何通过全局符号注册表创建和重用。还探讨了常用的内置Symbol,如Symbol.hasInstance用于自定义`instanceof`行为,Symbol.isConcatSpreadable控制数组`concat()`方法的合并方式,以及如何重构正则表达式的`match()`方法。总结中强调了Symbol在多库协作和减少代码误操作中的重要性。
2047





