ES6学习——类语法:Symbol.species在实例创建中的应用

来源:互联网 发布:linux 启动tomcat 编辑:程序博客网 时间:2024/06/06 07:16

在Symbol的章节我们大概介绍了一下species,这篇文章详细看一下规范中是如何调用的,以及我们在自定义类的时候可以怎么使用这个symbol。

我们拿Array.prototype.map举例:

规范22.1.3.15 Array.prototype.map ( callbackfn [ , thisArg ] ):

1. Let O be ToObject(this value).
2. ReturnIfAbrupt(O).
7. Let A be ArraySpeciesCreate(O, len).
8. ReturnIfAbrupt(A).


规范9.4.2.3 ArraySpeciesCreate(originalArray, length):

3. Let C be undefined.
4. Let isArray be IsArray(originalArray).
5. ReturnIfAbrupt(isArray).
6. If isArray is true, then
    a. Let C be Get(originalArray, "constructor").
    b. ReturnIfAbrupt(C).
    c. If IsConstructor(C) is true, then
        ......
    d. If Type(C) is Object, then
        i. Let C be Get(C, @@species).
        ii. ReturnIfAbrupt(C).
        iii. If C is null, let C be undefined.
7. If C is undefined, return ArrayCreate(length).
8. If IsConstructor(C) is false, throw a TypeError exception.
9. Return Construct(C, «length»).


我们应该注意ArraySpeciesCreate中的6.a,这里要取一次originalArray的constructor属性,并赋值给C,所以在重写这个Symbol.species的时候,应该复写成静态getter的形式,或者用Object.defineProperty。

下面我们详细看一下这两种形式:

class MyArray1 extends Array {static get [Symbol.species]() { // 静态getterreturn Array;}}var arr = new MyArray1(4),mapArr = arr.map(x=>x);trace(mapArr instanceof Array)//truetrace(mapArr instanceof MyArray1)//false

class MyArray1 extends Array {}Object.defineProperty(//Object.definePropertyMyArray1, Symbol.species, {value: Array});

上面两种形式的本质目的就是为了符合规范,其实就是让mapArr.constructor[Symbol.species]能取回一个Object。那么为什么不能直接在MyArray1上定义静态属性呢?如下:

MyArray1[Symbol.species] = Array

因为Array上已经有这个属性了,并且是只读的,只有一个getter,没有setter,不能进行赋值。在规范的22.1.2.5 get Array [ @@species ]:

Array[@@species] is an accessor property whose set accessor function is undefined. Its get accessor function performs the following steps:
    1. Return the this value.
The value of the name property of this function is "get [Symbol.species]".


NOTE Array prototype methods normally use their this object’s constructor to create a derived object. However, a subclass constructor may over-ride that default behaviour by redefining its @@species property.


如果Symbol.species返回null,规范ArraySpeciesCreate的7中就会自动使用默认的创建数组方法,即创建出来的是Array类型:

class MyArray3 extends Array {    static get [Symbol.species]() {        return null;    }}let result3 = new MyArray3().map(x => x);trace(result3 instanceof Array); // true



下面我们看一个自定义的类中如何使用这个Symbol.species:

class Foo {static get [Symbol.species]() { return this; }spawn() {return new this.constructor[Symbol.species]();//不需要写死返回实例类型}}class Bar extends Foo {static get [Symbol.species]() { return Foo; }//自定义需要返回的实例类型}var a = new Foo();var b = a.spawn();b instanceof Foo; // truevar x = new Bar();var y = x.spawn();y instanceof Bar; // falsey instanceof Foo; // true


其实规范中还有一种利用Symbol.species的不同形式,在Promise.all的API中,有兴趣的自己去看吧,不再这里说了。

*以上全部代码在Kinoma Studio中通过测试。


0 0
原创粉丝点击