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

标签: ES6 javascript function class Symbol
745人阅读 评论(0) 收藏 举报
分类:

在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中通过测试。


查看评论

ES6学习——新的语法:Symbols——Symbol.toPrimitive,Symbol.hasInstance,Symbol.toStringTag,Symbol.species

这节讲的这四个没有Symbol.iterator常见,但可能也会用到,由于浏览器对这些well-known symbols不是都支持,所以我们需要用Kinoma来测试这些特性。 先看比较简单...
  • kittyjie
  • kittyjie
  • 2016-01-06 15:03:52
  • 1906

TypeScript Symbols和迭代器

一、Symbols 1.介绍 自ECMScript2015起,symbol成为一种新的原生类型,就像number和string一样。symbol类型的值通过Symbol构造函数创建的。 Symb...
  • u011127019
  • u011127019
  • 2017-07-01 14:35:59
  • 627

ES6-Symbol类型

Symbol类型 1. 为了避免属性名的冲突,ES6新增了Symbol类型。Symbol可以产生一个独一无二的值。 let s1 = Symbol('a'); let s2 = S...
  • qiqingjin
  • qiqingjin
  • 2016-04-22 15:14:35
  • 904

runspec 的选项说明(spec2006官方文档的翻译)

runspec的使用 runspec [options] [list of benchmarks to run] 常用选项:(尽量使用长选项) --action| -a:指定runspec的...
  • zhangshuaiisme
  • zhangshuaiisme
  • 2016-12-08 16:40:14
  • 1461

error LNK2001: unresolved external symbol __imp__

  这是一个很常见的链接错误,像下面链接错误是因为找不到win32下面网络通信的库,因为这个库不常用,所以VC默认是不加载的: MyClient.obj : error LNK2001: unreso...
  • magictong
  • magictong
  • 2008-09-03 15:26:00
  • 8819

React学习之路二:从Hello World开始的初体验

       React最核心思想就是组件。组件就是独立的、可以重复利用的代码。这就是分而治之的思想,非常的牛逼。传统前端开发是把js、css和html文件分开进行管理,而基于组件的前端开发是把功能相...
  • u013418556
  • u013418556
  • 2018-02-24 17:18:11
  • 44

ES6常用的一些语法总结

1. let和const的使用 * let和const类似于javascript中的var的使用,都是用来声明变量的,只是都存在各自的特殊用法。 //javascript 只有全局作用域和函数...
  • u012862227
  • u012862227
  • 2017-01-16 18:43:16
  • 2090

RSPEC-入门学习

前言       要了解RSpec,我们首先需要了解什么是行为驱动开发(Behaviour Driven Development,简称BDD),BDD是一种融合了可接受性测试驱动计划(Acceptan...
  • chad20080808
  • chad20080808
  • 2014-05-29 15:06:56
  • 445

The Ultimate (DLL) Header File

 IntroductionEfficient and appropriate use of header files requires a few tricks. If you simply defi...
  • raymonzhao
  • raymonzhao
  • 2007-05-24 16:53:00
  • 417

es6 javascript的 class 类的基本语法

1 概述JavaScript 语言的传统方法是通过构造函数, 定义并生成新对象。 下面是一个例子。function Point(x, y) { this.x = x; this.y = y; } ...
  • qq_30100043
  • qq_30100043
  • 2016-12-09 10:28:30
  • 2363
    个人资料
    专栏达人 持之以恒
    等级:
    访问量: 37万+
    积分: 6067
    排名: 5184
    博客专栏
    最新评论