12.1 ECMAScript 6 中的可调用实体

在 ES6 中,有如下可调用的实体:

  • 传统的函数(通过函数表达式和函数声明创建)
  • 生成器函数(通过生成器函数表达式和生成器函数声明创建)
  • 箭头函数(只有一种表达式的形式)
  • 方法(通过对象字面量和类定义中的方法定义创建)
  • 生成器方法(通过对象字面量和类类定义的生成器方法定义创建)
  • 类(通过类表达式和类声明创建)

注意我区分了:

  • 这种实体:例如传统函数
  • 创建实体的语法:例如函数表达式和函数声明

尽管它们的表现差异很大(后面讲解),但是所有实体都是函数。例如:

> typeof (() => {}) // arrow function
'function'
> typeof function* () {} // generator function
'function'
> typeof class {} // class
'function'

接下来,我们详细学习每一种可调用实体。

12.1.1 ES6 中的调用方式

某些调用可以发生在任何地方,其它调用被限制在指定的区域。

12.1.1.1 可以在任何地方发生的调用

在 ES6 中有三种调用可以发生在任何地方:

  • 函数调用: func(3, 1)
  • 方法调用: obj.method('abc')
  • 构造器调用: new Constr(8)

对于函数调用,记住这点很重要:大多数 ES6 代码会被包含进模块,并且模块体隐式地设为了严格模式。

12.1.1.2 通过 super 调用的方式被限制在指定的区域

两种调用可以通过 super 关键字发生;它们的使用被限制在指定的区域:

  • 父方法调用: super.method('abc')

    仅在对象字面量或者继承类定义的方法定义中可用。

  • 父构造器调用: super(8)

    仅在继承类特殊的方法 constructor() 中可用。

12.1.1.3 非方法函数( non-method function )和方法

非方法函数和方法之间的区别在 ES6 中变得更加明显了。现在两者都有特殊的实体,并且只有它们能做相应的事情:

  • 箭头函数就是非方法函数。它从父作用域中拉取 this 和其它变量(“词法的 this ”)。
  • 方法定义就是方法。它支持 super ,指向父属性和实现父方法调用。

12.1.2 传统的函数

有些函数来自于 ES5 。有两种方式创建这些函数:

  • 函数表达式:
const foo = function (x) { ··· };
  • 函数声明:
function foo(x) { ··· }

this 规则:

  • 函数调用:在严格模式下, thisundefined ,宽松模式下为全局对象。
  • 方法调用: this 是方法调用消息的接收者(或者是 call/apply 的第一个参数)。
  • 构造器调用: this 是新创建的实例。

12.1.3 生成器函数

生成器函数在生成器章节介绍。它们的语法和传统的函数类似,但是有一个额外的星号:

  • 生成器函数表达式:
const foo = function* (x) { ··· };
  • 函数声明:
function* foo(x) { ··· }

this 规则如下所示。注意 this 绝不会指向当前生成器对象。

  • 函数/方法调用:和传统的函数一样处理 this 。该调用的返回值是生成器对象。
  • 构造器调用:在一个生成器函数中访问 this 会引起 ReferenceError 。构造器调用的结果是一个生成器对象。

12.1.4 方法定义

方法定义在对象字面量中出现:

let obj = {
    add(x, y) {
        return x + y;
    }, // comma is required
    sub(x, y) {
        return x - y;
    }, // comma is optional
};

在类定义中:

class AddSub {
    add(x, y) {
        return x + y;
    } // no comma
    sub(x, y) {
        return x - y;
    } // no comma
}

方法定义是唯一一个可以使用 super 指向父属性的地方。Only method definitions that use super produce functions that have the property [[HomeObject]], which is required for that feature (details are explained in the chapter on classes).

规则:

  • 函数调用:如果取出一个方法,像函数一样调用它,这个方法就表现得和传统函数一样了。
  • 方法调用:和传统函数一样,但是额外地允许你使用 super
  • 构造器调用:产生一个 TypeError

在类定义中,名为 constructor 的方法很特别,在后面会有解释。

12.1.5 生成器方法定义

生成器方法在生成器章节介绍。它的语法和函数定义类似,但是带有一个额外的星号:

let obj = {
    * generatorMethod(···) {
        ···
    },
};
class MyClass {
    * generatorMethod(···) {
        ···
    }
}

规则:

  • 调用一个生成器方法返回一个生成器对象。
  • 你可以使用 thissuper ,就像你在通常的方法定义中一样。

12.1.6 箭头函数

箭头函数在它自己的那一章讲解:

let squares = [1,2,3].map(x => x * x);

下面的变量词法上在箭头函数里(从父作用域中拉取):

  • arguments
  • super
  • this
  • new.target

规则:

  • 函数调用:词法的 this 等等。
  • 方法调用:你可以使用箭头函数作为方法,但是 this 仍然是词法的,并不指向方法调用消息的接收者。
  • 构造函数调用:产生一个 TypeError

12.1.7 类

类在它自己的那一章中讲解。

// Base class: no `extends`
class Point {
    constructor(x, y) {
        this.x = x;
        this.y = y;
    }
    toString() {
        return `(${this.x}, ${this.y})`;
    }
}

// This class is derived from `Point`
class ColorPoint extends Point {
    constructor(x, y, color) {
        super(x, y);
        this.color = color;
    }
    toString() {
        return super.toString() + ' in ' + this.color;
    }
}

constructor 方法很特殊,因为它“变成了”类。也就是说,类和构造器函数非常相似:

> Point.prototype.constructor === Point
true

规则:

  • 函数/方法调用:类不能以函数或者方法的形式调用(在类的那一章中解释了为什么)。
  • 构造器调用:遵循一个支持子类的协议。在基类中,创建一个实例,然后 this 指向它。一个继承类从它的父类中获取它的实例,这就是为什么要在访问 this 之前使用 super

results matching ""

    No results matching ""