上篇文章大體介紹了一些ES6的特性,以及如何在低版本瀏覽器中使用它們。本文是對class的詳解。
譯自Axel Rauschmayer的Classes in ECMAScript 6
另外,若是隻是想測試ES6,能夠到這個網站。html
藉助class 咱們能夠寫出這樣的代碼:es6
class Point { constructor(x, y) { this.x = x; this.y = y; } toString() { return '(' + this.x + ', ' + this.y + ')'; } } class ColorPoint extends Point { constructor(x, y, color) { super(x, y); this.color = color; } toString() { return super.toString() + ' in ' + this.color; } } let cp = new ColorPoint(25, 8, 'green'); cp.toString(); // '(25, 8) in green' console.log(cp instanceof ColorPoint); // true console.log(cp instanceof Point); // true
咱們能夠定義以下的class:瀏覽器
class Point { constructor(x, y) { this.x = x; this.y = y; } toString() { return '(' + this.x + ', ' + this.y + ')'; } }
咱們能夠像使用ES5標準中的constructor同樣實例化classbabel
> var p = new Point(25, 8); > p.toString() '(25, 8)'
實際上,class仍是用function實現的,並無爲js創造一個全新的class體系。ide
> typeof Point 'function'
可是,與function相比,它是不能直接調用的,也就是說必須得new出來函數
> Point() TypeError: Classes can’t be function-called
另外,它不會像function同樣會被hoisted(緣由是語義階段沒法解析到extends的內容)測試
foo(); // works, because `foo` is hoisted function foo() {} new Foo(); // ReferenceError class Foo {}
function functionThatUsesBar() { new Bar(); } functionThatUsesBar(); // ReferenceError class Bar {} functionThatUsesBar(); // OK
與函數同樣,class的定義表達式也有兩種,聲明形式、表達式形式。以前用的都是聲明形式,如下是表達式式的:網站
const MyClass = class Me { getClassName() { return Me.name; } }; let inst = new MyClass(); console.log(inst.getClassName()); // Me console.log(Me.name); // ReferenceError: Me is not defined
class定義體是隻能包含方法,不能包含屬性的(標準定義組織認爲原型鏈中不該包含屬性),屬性被寫在constructor中。如下是三種會用到的方法(constructor 、static method、 prototype method):this
class Foo { constructor(prop) { this.prop = prop; } static staticMethod() { return 'classy'; } prototypeMethod() { return 'prototypical'; } } let foo = new Foo(123);
以下圖([[Prototype]]表明着繼承關係)當對象被new出來,拿的是Foo.prototype : Object分支,從而能夠調prototype method
constructor,這個方法自己,表明了classprototype
> Foo === Foo.prototype.constructor true
constructor有時被稱爲類構造器。相較於ES5,它能夠調用父類的constructor(使用super())。
static methods。它們歸屬於類自己。
> typeof Foo.staticMethod 'function' > Foo.staticMethod() 'classy'
關於Getters and setters,它們的語法以下:
class MyClass { get prop() { return 'getter'; } set prop(value) { console.log('setter: '+value); } } > let inst = new MyClass(); > inst.prop = 123; setter: 123 > inst.prop 'getter'
方法名是能夠動態生成的
class Foo() { myMethod() {} } class Foo() { ['my'+'Method']() {} } const m = 'myMethod'; class Foo() { [m]() {} }
增長了迭代器的支持,須要給方法前面加一個*
class IterableArguments { constructor(...args) { this.args = args; } * [Symbol.iterator]() { for (let arg of this.args) { yield arg; } } } for (let x of new IterableArguments('hello', 'world')) { console.log(x); } // Output: // hello // world
經過extends,咱們能夠繼承其它實現constructor的函數或對象。須要注意一下,constructor與非constructor調用父類方法的途徑是不一樣的。
class Point { constructor(x, y) { this.x = x; this.y = y; } toString() { return '(' + this.x + ', ' + this.y + ')'; } } class ColorPoint extends Point { constructor(x, y, color) { super(x, y); // (A) this.color = color; } toString() { return super.toString() + ' in ' + this.color; // (B) } } > let cp = new ColorPoint(25, 8, 'green'); > cp.toString() '(25, 8) in green' > cp instanceof ColorPoint true > cp instanceof Point true
子類的原型就是它的父類
> Object.getPrototypeOf(ColorPoint) === Point true
因此,static method也被繼承了
class Foo { static classMethod() { return 'hello'; } } class Bar extends Foo { } Bar.classMethod(); // 'hello'
static方法也是支持調用父類的。
class Foo { static classMethod() { return 'hello'; } } class Bar extends Foo { static classMethod() { return super.classMethod() + ', too'; } } Bar.classMethod(); // 'hello, too'
關於子類中使用構造器,須要注意的是,調用this以前,須要調用super()
class Foo {} class Bar extends Foo { constructor(num) { let tmp = num * 2; // OK this.num = num; // ReferenceError super(); this.num = num; // OK } }
constructors是能夠被顯示覆蓋(override)的。
class Foo { constructor() { return Object.create(null); } } console.log(new Foo() instanceof Foo); // false
若是基類中不顯示定義constructor,引擎會生成以下代碼
constructor() {}
對於子類
constructor(...args) { super(...args); }
class C { m() {} } new C.prototype.m(); // TypeError
ES 6中,子類的使用方法以下:
class Point { constructor(x, y) { this.x = x; this.y = y; } ··· } class ColorPoint extends Point { constructor(x, y, color) { super(x, y); this.color = color; } ··· } let cp = new ColorPoint(25, 8, 'green');
原型鏈實現:
> const getProto = Object.getPrototypeOf.bind(Object); > getProto(Point) === Function.prototype true > getProto(function () {}) === Function.prototype true > getProto(Point.prototype) === Object.prototype true > getProto({}) === Object.prototype true