JS红宝书 数据类型第三节 Symbol类型下节

Symbol下的方法:

1、Symbol.asyncIterator

  根据ECMAScript规范,这个符号作为一个属性表示“一个方法,该方法返回对象默认的AsyncIterator”。由for-await-of语句使用,表示实现异步迭代器API的函数。for-await-of循环会利用这个函数执行异步迭代操作。

例:

        class Example{
            constructor(max){
                this.max=max
                this.asyncIdx=0
            }
            async*[Symbol.asyncIterator](){
                while(this.asyncIdx<this.max){
                    yield new Promise((resolve)=>resolve(this.asyncIdx++))
                }
            }
        }
        async function asyncCount(){
            let example=new Example(5)
            for await(const x of example){
                console.log(x)          
            }
        }
        // 输出:asyncCount()
        // 0 1 2 3 4

注意:Symbol.asyncIterator是ES2018规范定义的,因此只有版本非常新的浏览器支持它。

2、Symbol.hasInstance

  根据ECMAScript规范,这个符号作为一个属性表示“一个方法,该方法决定一个构造函器对象是否认可一个对象是它的实例”。由instanceof操作符使用,instanceof操作符可以用来确定一个对象实例的原型上是否有原型。

例:

        function Foo(){}
        let f=new Foo()
        console.log(f instanceof Foo)       //true

在ES6中,instanceof操作符会使用Symbol.hasInstance函数来确定关系,以Symbol.hasInstance为键的函数会执行同样的操作,只是操作数对调了一下。

        function Foo(){}
        let f=new Foo()
        console.log(Foo[Symbol.hasInstance](f))    //true

这个属性定义在Function的原型上,因此默认所有函数和类上都可以调用。由于instanceof操作符会在原型链上寻找这个属性定义,就跟在原型链上寻找其他属性一样,因此可以在继承的类上通过静态方法重新定义这个函数。

例:

  class Bar{}
        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
        console.log(Baz[Symbol.hasInstance](b))         //false
        console.log(b instanceof Baz)                   //false

3、Symbol.isConcatSpreadable

  根据ECMAScript规范,这个符号作为一个属性表示“一个布尔值,如果是true,则意味着对象应用Array.prototype.concat()打平其数组元素”。ES6中Array.prototype.concat()方法会根据接收到的对象类型选择如何将一个类数组对象拼接成数组实例。覆盖Symbol.isConcatSpreadable的值可以修改这个行为。

(1)数组对象默认情况下会被打平到已有的数组

例:

        let initial=['foo']
        let array=['bar']
        console.log(initial.concat(array))                  // ['foo', 'bar']

(2)false或假值会导致整个对象被追加到数组末尾。类对象默认情况下会被追加到数组末尾。

例:

        array[Symbol.isConcatSpreadable]==false
        console.log(initial.concat(array))                  //['foo', 'bar']

(3)true或真值会导致这个类数组对象被打平到数组实例。

例:

        let list={length:1,0:'baz'}                        
        console.log(initial.concat(list))                   //['foo', {…}]
        list[Symbol.isConcatSpreadable]=true
        console.log(initial.concat(list))                   //['foo', 'baz']

4、Symbol.iterator

  根据ECMAScript规范,这个符号作为一个属性表示“一个方法,该方法返回对象默认迭代器”。由for-of语句使用。换句话说,这个符号实现迭代器API的函数。

例:

       class Emitter{
            constructor(max){
                this.max=max
                this.id=0
            }
            *[Symbol.iterator](){
                while(this.id<this.max){
                    yield this.id++;
                }
            }
        }
        function count(){
            let emitter=new Emitter(5)
            for(const x of emitter){
                console.log(x)
            }
        }
        count()
        // 输出 0 1 2 3 4

5、Symbol.match

  根据ECMAScript规范,这个符号作为一个属性表示“一个正则表达方法,该方法用正则表达式去匹配字符串”。由String.prototype.match()方法使用。String.prototype.match()方法会使用以Symbol.match为键的函数来对正则表达式求值。

例:

        console.log('foobar'.match(/bar/))      
        //['bar', index: 3, input: 'foobar', groups: undefined]

给这个方法传入非正则表法式值会导致该值被转换为RegExp对象。如果想改变这种行为,让方法直接使用参数,则可以重新定义Symbol.match函数以取代默认正则表达式求值的行为,从而让match()方法使用非正则表达式实例。Symbol.match函数接收一个参数,就是调用match()方法的字符串实例,返回值没有限制。

例:

        class FooMatcher{
            static [Symbol.match](target){
                return target.includes('foo')
            }
        }
        console.log('foobar'.match(FooMatcher))     //true
        console.log('barbaz'.match(FooMatcher))     //false

6、Symbol.replace

  根据ECMAScript规范,这个符号作为一个属性表示“一个正则表达式方法,该方法替换一个字符串中匹配的子串”。由String.prototype.replace()方法使用。String.prototype.replace()方法会使用以Symbol.replace为键的函数来对正则表达式求值。

   console.log('foobaraz'.replace(/bar/,'qux'))     //fooquxaz

  给这个方法传入非正则表法式值会导致该值被转换为RegExp对象。如果想改变这种行为,让方法直接使用参数,则可以重新定义Symbol.replace函数以取代默认正则表达式求值的行为,从而让replace()方法使用非正则表达式实例。Symbol.replace函数接收一个参数,就是调用replace()方法的字符串实例和替换字符串,返回值没有限制。

        class FooReaplace {
            static [Symbol.replace](target, replacement) {
                return target.split('foo').join(replacement)
            }
        }
        console.log('barfoobaz'.replace(FooReaplace, 'qux'))                 //barquxbaz

        class StringReplacer {
            constructor(str) {
                this.str = str
            }
            [Symbol.replace](target, replacement) {
                return target.split(this.str).join(replacement)
            }
        }
        console.log('barfoobaz'.replace(new StringReplacer('foo'),'qux'))    //barquxbaz

7、Symbol.search

  根据ECMAScript规范,这个符号作为一个属性表示“一个正则表达式方法,该方法返回字符串中匹配正则表达式的索引,由String.prototype.search()方法使用”。String.prototype.search()方法会使用以Symbol.search为键的函数来对正则表达式求值。正则表达式的原型上默认有这个函数的定义,因此所有正则表达式实例默认是这个String方法有效值。

  console.log('foobar'.search(/bar/))         //3

  给这个方法传入非正则表法式值会导致该值被转换为RegExp对象。如果想改变这种行为,让方法直接使用参数,则可以重新定义Symbol.search函数以取代默认正则表达式求值的行为,从而让search()方法使用非正则表达式实例。Symbol.search函数接收一个参数,就是调用match()方法的字符串实例,返回值没有限制。

        class FooSearch{
            static [Symbol.search](target){
                return target.indexOf('foo')
            }
        }
        console.log('foobar'.search(FooSearch))     //0
        console.log('barfoo'.search(FooSearch))     //3
        console.log('barbaz'.search(FooSearch))     //-1

8、Symbol.species

  根据ECMAScript规范,这个符号作为一个属性表示"一个函数值,该函数值作为创建派生对象的构造函数。"这个属性在内置类型中最为常见,用于对内置类型实例方法的返回值暴露实例化派生对象的方法。用Symbol.species定义静态的获取器(getter)方法,可以覆盖创建实例的原型定义。

        class Bar extends Array{}
        class Baz extends Array{
            static get [Symbol.species](){
                return Array
            }
        }
        let bar=new Bar()
        console.log(bar instanceof Array)       //true
        console.log(bar instanceof Bar)         //true
        console.log(bar instanceof Baz)         //false

        let baz=new Baz()
        console.log(baz instanceof Array)       //true
        console.log(baz instanceof Bar)         //false
        console.log(baz instanceof Baz)         //true

        baz=baz.concat('baz')
        console.log(baz instanceof Array)       //true
        console.log(baz instanceof Bar)         //false
        console.log(baz instanceof Baz)         //false

9、Symbol.split

  根据ECMAScript规范,这个符号作为一个属性表示"一个正则表达式方法,该方法在匹配正则表达式的索引位置拆分字符串。由String.prototype.split()方法使用"。String.prototype.split()方法会使用以Symbol.split为键的函数来对正则表达式求值。正则表达式的原型上默认有这个函数的定义,因此所有正则表达式实例默认是这个String方法的有效参数。

   console.log('foobarbaz'.split(/bar/))       //['foo','baz']

  给这个方法传入非正则表法式值会导致该值被转换为RegExp对象。如果想改变这种行为,让方法直接使用参数,则可以重新定义Symbol.split函数以取代默认正则表达式求值的行为,从而让split()方法使用非正则表达式实例。Symbol.split函数接收一个参数,就是调用match()方法的字符串实例,返回值没有限制。

        class FooSplitter{
            static [Symbol.split](target){
                return target.split('foo')
            }
        }
        console.log('barfoobaz'.split(FooSplitter))         // ['bar', 'baz']

10、Symbol.toPrimitive

  根据ECMAScript规范,这个符号作为一个属性表示"一个方法,该方法将对象转换成相应的原始值。由ToPrimitive抽象操作使用。"很多内置操作都会强制将对象转化为原始值,包括字符串、数值和未指定的原始类型。对于一个自定义的对象实例,通常在这个实例的Symbol.toPrimitive属性上定义一个函数可以改变默认行为。

        class Bar{
            constructor(){
                this[Symbol.toPrimitive]=function(hint){
                    switch (hint){
                        case 'number':
                            return 3
                        case 'string':
                            return 'string bar'
                        case 'default':
                        default:
                            return 'default bar'
                    }
                }
            }
        }
        let bar=new Bar()
        console.log(3+bar)              //3default bar
        console.log(3-bar)              //0
        console.log(String(bar))        //string bar

11、Symbol.toStringTag

  根据ECMAScript规范,这个符号作为一个属性表示"一个字符串,该字串用于创建对象的默认字符串描述。由内置方法Object.prototype.toString()使用。"

        let s=new Set()
        console.log(s)                          //Set(0) {}
        console.log(s.toString())               //[object Set]
        console.log(s[Symbol.toStringTag])      //Set

12、Symbol.unscopables

  根据ECMAScript规范,这个符号作为一个属性表示"一个对象,该对象所有的以及继承的属性。都会从关联对象的with环境绑定中排除"。设置这个符号并让其映射对应属性的键值为true,就可以阻止该属性出现在with环境绑定中。

        let o={foo:'bar'}
        with(o){
            console.log(foo)            //bar
        }
        o[Symbol.unscopables]={
            foo:true
        }
        with(o){
            console.log(foo)            //foo is not defined
        }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值