浅谈Symbol及对其内部属性的理解

一、内置方法

  • asyncIterator:异步迭代器
  • iterator:迭代器
  • for
  • keyFor
  • hasInstance
  • isConcatSpreadable
  • match
  • matchAll
  • replace
  • split
  • search
  • species
  • toPrimitive
  • toStringTag
  • unscopables
  • useSetter
  • useSimple

二、部分API解析

1、异步迭代器(asyncIterator)

  • 定义:指定了一个对象的默认的异步迭代器,如果一个对象设置了这个属性,那么它就是异步可迭代对象,可用于for await…of 循环。
  • 给一个对象添加asyncIterator属性
let as_iterator = new Object();
as_iterator[Symbol.asyncIterator] = async function* () {
    yield 'hello';
    yield 'waiting';
    yield 'ending';
}
(async()=>{
    for await(let a of as_iterator) {
        console.log(a);
        //	hello
        //	waiting
        //	ending
    }
})();

【注:】暂时没有设置了[Symbol.asyncIterator]这个属性的JavaScript对象

2、迭代器(iterator)

  • 定义:
    为每一个对象定义了默认的迭代器,该迭代器可被【for…of】循环使用

  • 拥有迭代器属性的对象:

    • String
    • Map
    • Set
    • Array
    • arguments
    • … …
  • 自定义迭代器:
    1.利用generator函数:

let my_iterator = {
    [Symbol.iterator] : function* () {
        yield 'hello';
        yield 'waiting';
        yield 'ending';
    }
}
console.log([...my_iterator]);	//	['hello', 'waiting', 'ending']

2.数据结构默认的Iterator接口,可以通过for…of使用。解构赋值用的也是Iterator接口。

const other_iterator = {
    data: ['hello', 'welcome', 'world'],
    [Symbol.iterator]() {
        const self = this;
        let ind = 0;
        return {
            next() {
                if (ind < self.data.length) {
                    return {
                        value: self.data[ind++],
                        one: false
                    }
                } else {
                    return {
                        value: undefined,
                        done: true
                    }
                }
            }
        }
    },
    a: 1,
    b: 2
}
let abs = other_iterator[Symbol.iterator]()
console.log(abs.next());    //  {value: 'hello', one: false}
console.log(abs.next());    //  {value: 'welcome', one: false}
console.log(abs.next());    //  {value: 'world', one: false}
console.log(abs.next());    //  {value: undefined, done: true}

3、for

  • 定义:不同的变量可以使用同一个Symbol值,Symbol.for()方法接收一个参数,然后查找是否有以该参数作为名称的Symbol值,如果有就返回这个Symbol值,否则就新建一个以该参数为名称的Symbol值。
let a = Symbol('symbol')
let b = Symbol('symbol')
console.log(a === b);	//	false

let symbol_a = Symbol.for('symbol');
let symbol_b = Symbol.for('symbol');
console.log(symbol_a === symbol_b);	//	true

4、keyFor

  • 定义: 返回一个已使用的 Symbol 类型值的key,用来检测该参数作为名称的 Symbol 值是否已被使用
/** Symbol.keyFor */
let a = Symbol.for('symbol');
let b = Symbol.keyFor(a)
console.log(b); //  symbol
console.log(a); //  Symbol(symbol)
console.log(a === b);   //  false

5、hasInstance

  • 定义: 当我们使用instanceof这个方法去检测对象A是不是B 的实例的时候,实际上B就是调用的 B[Symbol.hasInstance] 这个方法。
    1、常规使用
class Event {}
let e = new Event;
console.log(e instanceof Event);    //  true
console.log(Event[Symbol.hasInstance](e));  //  true

2、更改 [Symbol.hasInstance] 指向

class my_instance {
    static [Symbol.hasInstance](params) {
        typeof params   
    }
}
let a = new my_instance();
console.log(a instanceof my_instance);  //  false
console.log(my_instance[Symbol.hasInstance](a));    //  undefined

6、isConcatSpreadable

  • 定义: 当我们使用 Array.prototype.concat 这个方法时,可以利用这个属性去控制是否展开合并的数组。
/* isConcatSpreadable */

const arr1 = [1, 2, 3, 4]
const arr2 = ['a', 'c', 'b', 8]
let arr = arr1.concat(arr2)
console.log(arr);   //  [1, 2, 3, 4, 'a', 'c', 'b', 8]

arr2[Symbol.isConcatSpreadable] = false;
// arr1[Symbol.isConcatSpreadable] = false;
let arg = arr1.concat(arr2)
console.log(arg);   //  [1, 2, 3, 4, Array(4)]

7、match

  • 定义: 指定了匹配的是正则表达式,而不是字符串。String.prototype.match 会调用此方法。
/*   match   */

let regexp = /testssymbolmatch/;
regexp[Symbol.match] = false
console.log('/test/'.startsWith(regexp));   //  false
console.log('/test/'.endsWith(regexp));     //  false
console.log('/testssymbolmatch/'.startsWith(regexp));   //  true
console.log('/testssymbolmatch/'.endsWith(regexp));     //  true

当不设置 [Symbol.match] 这个属性为 false的时候:

console.log('/testssymbolmatch/'.startsWith(/testssymbolmatch/));

在这里插入图片描述
Uncaught TypeError: First argument to String.prototype.startsWith must not be a regular expression

8、matcAll

  • 定义: 返回一个迭代器,该迭代器根据字符串生成正则表达式的匹配项。可以被 [String.prototype.matchAll] 调用
/*   matchAll   */

const  exp = /\d+/g
const str ='2022-05-11 17:13:14';
let res = exp[Symbol.matchAll](str)
console.log(res);   //  RegExpStringIterator {}
console.log(...res)
/**
 * ['2022', index: 0, input: '2022-05-11 17:13:14', groups: undefined]
 * ['05', index: 5, input: '2022-05-11 17:13:14', groups: undefined] 
 * ['11', index: 8, input: '2022-05-11 17:13:14', groups: undefined] 
 * ['17', index: 11, input: '2022-05-11 17:13:14', groups: undefined] 
 * ['13', index: 14, input: '2022-05-11 17:13:14', groups: undefined]
 * ['14', index: 17, input: '2022-05-11 17:13:14', groups: undefined]
 */

9、replace

  • 定义: 指定了当一个字符串替换所匹配字符串时调用的方法。【String.prototype.replace () 】会调用此方法。
    该方法是正则(RegExp)原型上的一个方法,用来解析【String.prototype.replace () 】执行的时候传递进来的正则表达式,并对正则表达式匹配后的结果进行求值
let publicStr = 'anfdsvka fahF KJ'

RegExp.prototype[Symbol.replace] = () =>{
    return 'qqq'
}
let s = publicStr.replace(/\a/g,'2')
console.log(s); //  'qqq'

10、split

  • 定义: 指向一个正则表达式的索引处分隔字符串的方法。此方法通过【 String.prototype.split() 】调用。
    其也是正则原型上的一个方法,在字符串使用split方法的时候会调用改方法。
RegExp.prototype[Symbol.split] = () => {
    return [1, 2, 3];
}
s = publicStr.split(/\n/)
console.log(s); //  [1, 2, 3]

11、search

  • 定义: 指定了一个搜索方法,该方法接受一个正则表达式,该方法返回的是字符串中匹配到正则表达式的索引。此方法通过【String.prototype.search()】来调用。

1、正常使用:

let publicStr = 'anfdsvka fahF KJ'
let s= publicStr.search(/\a/g)
console.log(s);	// 0

2、更改正则原型上的此方法

RegExp.prototype[Symbol.search] = () => {
    return -1;
}
console.log(s);	// -1

12、species

  • 定义: 是个函数值属性,其被构造函数用以创建派生对象。
    该属性在内置类型中最常用,用于对内置类型实例方法的返回值暴露实例化派生对象的方法。
    基本使用:
class A extends Array { }
let a = new A;

console.log(a instanceof A);    //  true
console.log(a instanceof Array);    //  true

a.concat('123');
console.log(a instanceof A);    //  true
console.log(a instanceof Array);    //  true

用 Symbol.species 定义静态的获取器(getter),可以覆盖新创建实例的原型定义:

class B extends Array {
    static get [Symbol.species]() {
        return Array;
    }
}
let b = new B;

console.log(b instanceof B);    //  true
console.log(b instanceof Array);    //  true

b = b.concat('3121');
console.log(b instanceof B);    //  fales
console.log(b instanceof Array);    //  true

13、 toPrimitive

  • 定义: 是一个内置的 Symbol 值,它是作为对象的函数值属性存在的,当一个对象转换为对应的原始值时,会调用此函数。
const p1 = {
    [Symbol.toPrimitive](state) {
        switch (state) {
            case 'number':
                return 123;
            case 'string':
                return 'abc';
            default:
                return NaN;
        }
    }
}
console.log(p1);    //  { [Symbol(Symbol.toPrimitive)]: [Function: [Symbol.toPrimitive]] }
console.log(+p1);   //  123
console.log(Number(p1));    //  123
console.log(String(p1));    //  'abc'

14、toStringTag

  • 定义: 是一个内置 symbol,它通常作为对象的属性键使用,对应的属性值应该为字符串类型,这个字符串用来表示该对象的自定义类型标签,通常只有内置的 Object.prototype.toString() 方法会去读取这个标签并把它包含在自己的返回值里。
class Fn {
    [Symbol.toStringTag]= 'Fn';
}
Fn.prototype[Symbol.toStringTag] = 'Fn';
let f = new Fn;
console.log({}.toString.call(f));	//	'[object Fn]'

15、unscopables

  • 定义: 指用于指定对象值,其对象自身和继承的从关联对象的 with 环境绑定中排除的属性名称。
const publicObj = {
    a: '123',
    b: '234',
    c: undefined
}
publicObj[Symbol.unscopables] = {
    a: true,
    b: false
}

with(publicObj) {
    console.log(a); //  Uncaught ReferenceError: a is not defined
    console.log(b); //  '234'
    console.log(c); //  undefined
}

三、总结

  1. asyncIterator 暂时无设置有该属性的JS对象;
  2. iterator 迭代器,是在开发中可能会经常涉及到的一个Symbol属性,拥有该属性的数据类型包含:String、Array、arguments、Set、Map等;
  3. hasInstance 在使用instanceof方法检测数据类型的时候,会优先调用此方法;
  4. 正则对象的原型上的方法包含:match、matcAll、replace、split、search
  5. toStringTag 在使用 Object.prototype.toString() 去检测数据类型的时候,会优先调用 Symbol.toStringTag 这个方法
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值