今天看啥  ›  专栏  ›  sayhelloworld

Symbol.hasInstance

sayhelloworld  · 简书  ·  · 2021-04-24 11:21

Symbol.hasInstance
根据 ECMAScript 规范,这个符号作为一个属性表示“一个方法,该方法决定一个构造器对象是否
认可一个对象是它的实例。由 instanceof 操作符使用”。 instanceof 操作符可以用来确定一个对象
实例的原型链上是否有原型。 instanceof 的典型使用场景如下:
function Foo() {}
let f = new Foo();
console.log(f instanceof Foo); // true
class Bar {}
let b = new Bar();
console.log(b instanceof Bar); // true
在 ES6 中, instanceof 操作符会使用 Symbol.hasInstance 函数来确定关系。以 Symbol.
hasInstance 为键的函数会执行同样的操作,只是操作数对调了一下:
function Foo() {}
let f = new Foo();
console.log(Foo Symbol.hasInstance ); // true
class Bar {}
let b = new Bar();
console.log(Bar Symbol.hasInstance ); // true
这个属性定义在 Function 的原型上,因此默认在所有函数和类上都可以调用。由于 instanceof
操作符会在原型链上寻找这个属性定义,就跟在原型链上寻找其他属性一样,因此可以在继承的类上通
过静态方法重新定义这个函数:
class Bar {}
class Baz extends Bar {
static Symbol.hasInstance {
return false;
}
}
let b = new Baz();
console.log(Bar Symbol.hasInstance ); // true
console.log(b instanceof Bar); // true
console.log(Baz Symbol.hasInstance ); // false
console.log(b instanceof Baz); // false

  1. Symbol.isConcatSpreadable
    根据 ECMAScript 规范,这个符号作为一个属性表示“一个布尔值,如果是 true ,则意味着对象应
    该用 Array.prototype.concat() 打平其数组元素”。ES6 中的 Array.prototype.concat() 方法会
    根据接收到的对象类型选择如何将一个类数组对象拼接成数组实例。覆盖 Symbol.isConcat-
    Spreadable 的值可以修改这个行为。
    数组对象默认情况下会被打平到已有的数组, false 或假值会导致整个对象被追加到数组末尾。类
    数组对象默认情况下会被追加到数组末尾, true 或真值会导致这个类数组对象被打平到数组实例。其
    他不是类数组对象的对象在 Symbol.isConcatSpreadable 被设置为 true 的情况下将被忽略。
    let initial = ['foo'];
    let array = ['bar'];
    console.log(array[Symbol.isConcatSpreadable]); // undefined
    console.log(initial.concat(array)); // ['foo', 'bar']
    array[Symbol.isConcatSpreadable] = false;
    console.log(initial.concat(array)); // ['foo', Array(1)]let arrayLikeObject = { length: 1, 0: 'baz' };
    console.log(arrayLikeObject[Symbol.isConcatSpreadable]); // undefined
    console.log(initial.concat(arrayLikeObject)); // ['foo', {...}]
    arrayLikeObject[Symbol.isConcatSpreadable] = true;
    console.log(initial.concat(arrayLikeObject)); // ['foo', 'baz']
    let otherObject = new Set().add('qux');
    console.log(otherObject[Symbol.isConcatSpreadable]); // undefined
    console.log(initial.concat(otherObject)); // ['foo', Set(1)]
    otherObject[Symbol.isConcatSpreadable] = true;
    console.log(initial.concat(otherObject)); // ['foo']
  2. 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() 方法返回,也可以隐式地通过生成器函数返回:
    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
    注意 迭代器的相关内容将在第 7 章详细介绍。
  3. Symbol.match
    根据 ECMAScript 规范,这个符号作为一个属性表示“一个正则表达式方法,该方法用正则表达式
    去匹配字符串。由 String.prototype.match() 方法使用”。 String.prototype.match() 方法会使
    用以 Symbol.match 为键的函数来对正则表达式求值。正则表达式的原型上默认有这个函数的定义,
    因此所有正则表达式实例默认是这个 String 方法的有效参数:
    console.log(RegExp.prototype[Symbol.match]);
    // ƒ Symbol.match { [native code] }
    console.log('foobar'.match(/bar/));
    // ["bar", index: 3, input: "foobar", groups: undefined]
    给这个方法传入非正则表达式值会导致该值被转换为 RegExp 对象。如果想改变这种行为,让方法
    直接使用参数,则可以重新定义 Symbol.match 函数以取代默认对正则表达式求值的行为,从而让
    match() 方法使用非正则表达式实例。 Symbol.match 函数接收一个参数,就是调用 match() 方法的
    字符串实例。返回的值没有限制:
    class FooMatcher {
    static Symbol.match {
    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 {
    return target.includes(this.str);
    }
    }
    console.log('foobar'.match(new StringMatcher('foo'))); // true
    console.log('barbaz'.match(new StringMatcher('qux'))); // false
    Symbol.replace
    根据 ECMAScript 规范,这个符号作为一个属性表示“一个正则表达式方法,该方法替换一个字符
    串中匹配的子串。由 String.prototype.replace() 方法使用”。 String.prototype.replace()
    方法会使用以 Symbol.replace 为键的函数来对正则表达式求值。正则表达式的原型上默认有这个函
    数的定义,因此所有正则表达式实例默认是这个 String 方法的有效参数:
    console.log(RegExp.prototype[Symbol.replace]);
    // ƒ Symbol.replace { [native code] }
    console.log('foobarbaz'.replace(/bar/, 'qux'));
    // 'fooquxbaz'
    给这个方法传入非正则表达式值会导致该值被转换为 RegExp 对象。如果想改变这种行为直接使用参数,可以重新定义 Symbol.replace 函数以取代默认对正则表达式求值的行为,从而让
    replace() 方法使用非正则表达式实例。 Symbol.replace 函数接收两个参数,即调用 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"
  4. Symbol.search
    根据 ECMAScript 规范,这个符号作为一个属性表示“一个正则表达式方法,该方法返回字符串中
    匹配正则表达式的索引。由 String.prototype.search() 方法使用”。 String.prototype.search()
    方法会使用以 Symbol.search 为键的函数来对正则表达式求值。正则表达式的原型上默认有这个函数
    的定义,因此所有正则表达式实例默认是这个 String 方法的有效参数:
    console.log(RegExp.prototype[Symbol.search]);
    // ƒ Symbol.search { [native code] }
    console.log('foobar'.search(/bar/));
    // 3
    给这个方法传入非正则表达式值会导致该值被转换为 RegExp 对象。如果想改变这种行为,让方法
    直接使用参数,可以重新定义 Symbol.search 函数以取代默认对正则表达式求值的行为,从而让
    search() 方法使用非正则表达式实例。 Symbol.search 函数接收一个参数,就是调用 match() 方法
    的字符串实例。返回的值没有限制:
    class FooSearcher {
    static Symbol.search {
    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 {
    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
  5. 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
    bar = bar.concat('bar');
    console.log(bar instanceof Array); // true
    console.log(bar instanceof Bar); // true
    let baz = new Baz();
    console.log(baz instanceof Array); // true
    console.log(baz instanceof Baz); // true
    baz = baz.concat('baz');
    console.log(baz instanceof Array); // true
    console.log(baz instanceof Baz); // false
  6. Symbol.split
    根据 ECMAScript 规范,这个符号作为一个属性表示“一个正则表达式方法,该方法在匹配正则表
    达式的索引位置拆分字符串。由 String.prototype.split() 方法使用”。 String.prototype.
    split() 方法会使用以 Symbol.split 为键的函数来对正则表达式求值。正则表达式的原型上默认有
    这个函数的定义,因此所有正则表达式实例默认是这个 String 方法的有效参数:
    console.log(RegExp.prototype[Symbol.split]);
    // ƒ Symbol.split { [native code] }
    console.log('foobarbaz'.split(/bar/));
    // ['foo', 'baz']



原文地址:访问原文地址
快照地址: 访问文章快照