15.3 类的细节
我们到目前为止看到的是类的概要。如果对类的背后原理感兴趣,那就继续阅读下去。让我们以类的语法开始,下面是一个来自于《 Sect. A.4 of the ECMAScript 6 specification 》的经过稍微修改的版本。
ClassDeclaration:
"class" BindingIdentifier ClassTail
ClassExpression:
"class" BindingIdentifier? ClassTail
ClassTail:
ClassHeritage? "{" ClassBody? "}"
ClassHeritage:
"extends" AssignmentExpression
ClassBody:
ClassElement+
ClassElement:
MethodDefinition
"static" MethodDefinition
";"
MethodDefinition:
PropName "(" FormalParams ")" "{" FuncBody "}"
"*" PropName "(" FormalParams ")" "{" GeneratorBody "}"
"get" PropName "(" ")" "{" FuncBody "}"
"set" PropName "(" PropSetParams ")" "{" FuncBody "}"
PropertyName:
LiteralPropertyName
ComputedPropertyName
LiteralPropertyName:
IdentifierName /* foo */
StringLiteral /* "foo" */
NumericLiteral /* 123.45, 0xFF */
ComputedPropertyName:
"[" Expression "]"
观察之后,得出两个结论:
- 被继承的值可以产生于任何表达式,这意味着可以写出如下的代码:
class Foo extends combine(MyMixin, MySuperClass) {}
- 允许方法之间有分号。
15.3.1 各种检查
- 错误检查:类名不能是
eval
或arguments
;类元素名字不允许重复;名字constructor
只能作为普通的方法名,不能用作 getter 、 setter 或者生成器方法。 - 类不能像函数一样调用。如果像函数一样调用,则会抛出
TypeException
异常。 - 原型方法不能用作构造器:
class C {
m() {}
}
new C.prototype.m(); // TypeError
15.3.2 属性的特性( Attributes of properties )
Class declarations create (mutable) let bindings. 对于一个给定的类 Foo
:
- 静态的方法
Foo.*
是可写的和可配置的,但不可枚举。使它们可写就允许动态赋值。 一个构造器和它的属性
prototype
对象有一个不变的连接:Foo.prototype
是不可写的,不可枚举的,不可配置的。Foo.prototype.constructor
是不可写的,不可枚举的,不可配置的。
原型方法
Foo.prototype.*
是可写的和可配置的,但是不可枚举。
注意在对象字面量中的方法定义会产生可枚举的属性。