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

原创 2016年01月13日 09:11:13

在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]() { // 静态getter
		return Array;
	}
}

var arr = new MyArray1(4),mapArr = arr.map(x=>x);
trace(mapArr instanceof Array)//true
trace(mapArr instanceof MyArray1)//false

class MyArray1 extends Array {
}

Object.defineProperty(//Object.defineProperty
	MyArray1, 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; // true

var x = new Bar();
var y = x.spawn();
y instanceof Bar; // false
y instanceof Foo; // true


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

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


相关文章推荐

js获取颜色,颜色3中类型的转换

#div {             height:400px;             width:400px;             border:1px solid blue;    ...

javascript 十六进制与RGB颜色值的相互转换

转自:http://www.zhangxinxu.com/wordpress/?p=646   一、关于颜色的表示 颜色的表示方式不知一种,从photoshop的取色面板就可以看出,如下: ...
  • zzjiadw
  • zzjiadw
  • 2011年11月30日 10:29
  • 12047

ES6学习——新的语法:Symbols——Symbol.iterator

ES6中内置了一些Symbol,其中最重要的一个恐怕就是Symbol.iterator了,相当于迭代器的接口,只有对象里有这个symbol的属性,才可以认为此对象是可迭代的。 我们先看一下规范中对这...

ES6学习——类语法:继承中的实例构造过程

ES6的类中有个constructor函数是用来当构造函数的,如果你不写这个函数,ES6规范中会按照一定的条件给你自动添加上,在规范的14.5.14章节中有这样的描述: ClassTail : Cla...

ECMAScript 6 学习系列课程 (ES6 Symbol语法的使用)

ES5的对象属性名都是字符串,这容易造成属性名的冲突。比如,你使用了一个他人提供的对象,但又想为这个对象添加新的方法(mixin模式),新方法的名字就有可能与现有方法产生冲突。如果有一种机制,保证每个...

ES6学习——类语法:继承中的原型链

上篇文章中我们讲了些类的基本概念,其中提到ES6中的类语法是对原型继承的一种封装。JS的原型继承一共有两条原型链,显示和隐式,那么在类继承的语法中,这两条原型链又是怎么样的呢? 继续使用上篇文章中的例...

ES6学习——类语法:基本概念介绍

许多人一直说javascripr语法中没有类语法,不利于大型面向对象的项目开发。ES6中终于在千呼万唤中加入了类语法,但实质上还是对原型继承的一种封装,写起来会比较直观,我们知道OO的三大特性:封装,...

ES6学习——类语法:super和new.target

这里为什么把super拿出来单独讲一下呢?可能有人要说,super谁不会用,先看个例子,你就知道super不是那么简单: class ParentA { constructor() { this.i...

ES6学习——新的语法:数组解构(Array Destructuring)

上一篇文章讲了Object的解构,这篇讲一下Array的解构,概念大同小异,只是写法会有一些不同,先看个简单的例子: let [x, y] = ['a', 'b','c']; // x = 'a'; ...

ES6学习——新的语法:Arrow Functions

Arrow Functions并不是什么新鲜玩意了,在Java 8和Apple Swift语言中也都有这种写法,只不过有的语言用单箭头(->),JS中用双箭头(=>),大同小异,单箭头更像C或者C++...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:ES6学习——类语法:Symbol.species在实例创建中的应用
举报原因:
原因补充:

(最多只允许输入30个字)