《JavaScript高级程序设计》(第4版)阅读笔记(十一)

这篇文章继续分享第三章的内容,现在讲到了Symbol的内容。

 

8. Symbol.iterator
 

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

for-of 循环这样的语言结构会利用这个函数执行迭代操作。循环时,它们会调用以 Symbol.iterator 为键的函数,并默认这个函数会返回一个实现迭代器API的对象。很多时候,返回的
对象是实现该API的 Generator(生成器)
 

class Foo {
*[Symbol.iterator]() {}
} 
let f = new Foo();
console.log(f[Symbol.iterator]());
// Generator {<suspended>}

技术上,这个由 Symbol.iterator 函数生成的对象应该通过其 next() 方法陆续返回值。可以通过显式地调用 next() 方法返回,也可以隐式地通过生成器函数返回。(for of循环就是隐式地调用next方法,让生成器函数返回值)
 

class Emitter {
    constructor(max) {
    this.max = max;this.idx = 0;
    } 
    *[Symbol.iterator]() {
        while(this.idx < this.max) {
            yield this.idx++;
        }
     }
}

function count() {
    let emitter = new Emitter(5);
    for (const x of emitter) {
        console.log(x);
    }
} 

count();
// 0
// 1
// 2
// 3
// 4

9. Symbol.match
 

根据ECMAScript规范,这个符号作为一个属性表示“一个正则表达式方法,该方法用正则表达式去匹配字符串。由String.prototype.match() 方法使用”。
 

String.prototype.match() 方法会使用以Symbol.match 为键的函数来对正则表达式求值。正则表达式的原型上默认有这个函数的定义,因此所有正则表达式实例默认是这个 String 方法的有效参数。(我的理解是,String.prototype.match方法调用的时候,实际上会去调用一个函数,哪个函数呢?就是match的参数的[Symbol.match]方法。因为正则表达式原型上就有这个方法,所以String.prototype.match方法的参数可以是正则表达式)

console.log(RegExp.prototype[Symbol.match]);
// f [Symbol.match]() { [native code] }
console.log('foobar'.match(/bar/));
// ["bar", index: 3, input: "foobar", groups:
undefined]

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

Symbol.match 函数接收一个参数,就是调用 match() 方法的字符串实例。返回的值没有限制。

(下面有两个例子,第一个例子中,[Symbol.match]方法是类的静态方法(static),所以传入的参数就是类本身,通过类来找到这个方法,在这个方法的target参数这里,拿到的是调用match方法的字符串实例,然后比对这个字符串里也没有出现某个子字符串;第二个例子与第一个例子类似,但第二个例子的[Symbol.match]方法不是静态方法,所以传入的参数是类的实例,通过实例的原型找到这个方法。)

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

class StringMatcher {
    constructor(str) {
        this.str = str;
    }
    [Symbol.match](target) {
        return target.includes(this.str);
    }
} 
console.log('foobar'.match(new StringMatcher('foo'))); // true
console.log('barbaz'.match(new StringMatcher('qux'))); // false

10. Symbol.replace

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

String.prototype.replace() 方法会使用以Symbol.replace 为键的函数来对正则表达式求值。正则表达式的原型上默认有这个函数的定义,因此所有正则表达式实例默认是这个 String 方法的有效参数(跟上面一个方法类似,String.prototype.replace方法调用的时候,会去调用参数的[Symbol.replace]方法)

console.log(RegExp.prototype[Symbol.replace]);
// f [Symbol.replace]() { [native code] }
console.log('foobarbaz'.replace(/bar/,'qux'));
// 'fooquxbaz'

给这个方法传入非正则表达式值会导致该值被转换为 RegExp 对象。如果想改变这种行为,让方法直接使用参数,可以重新定义Symbol.replace 函数以取代默认对正则表达式求值的行为,从而让 replace() 方法使用非正则表达式实例。(这个也跟上面那个类似)

Symbol.replace 函数接收两个参数,即调用 replace() 方法的字符串实例替换字符串。返回的值没有限制。

下面的两个例子也是一个[Symbol.replace]方法是类的静态方法,另一个是类的原型方法。

class FooReplacer {
    static [Symbol.replace](target,replacement) {
    return
        target.split('foo').join(replacement);
    }
} 
console.log('barfoobaz'.replace(FooReplacer,'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"

11. Symbol.search

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

console.log(RegExp.prototype[Symbol.search]);
// f [Symbol.search]() { [native code] }
console.log('foobar'.search(/bar/));
// 3

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

下面的例子也是分别从类的静态方法和原型上的方法来展示了对[Symbol.search]方法重写的作用。

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


class StringSearcher {
    constructor(str) {
        this.str = str;
    } 
    [Symbol.search](target) {
        return target.indexOf(this.str);
    }
} 
console.log('foobar'.search(new StringSearcher('foo'))); // 0
console.log('barfoo'.search(new StringSearcher('foo'))); // 3
console.log('barbaz'.search(new StringSearcher('qux'))); // -1

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值