ES6新特性5:類(Class)和繼承(Extends)


本文摘自ECMAScript6入門,轉載請注明出處。

 

一、類(Class)

  1.基本語法

  JavaScript語言的傳統方法是通過構造函數,定義並生成新對象。下面是一個例子

function Point(x, y) {
    this.x = x;
    this.y = y;
}

Point.prototype.toString = function () {
    return '(' + this.x + ', ' + this.y + ')';
};

var p = new Point(1, 2);

 

  ES6提供了更接近傳統語言的寫法,引入了Class(類)這個概念,作為對象的模板。通過class關鍵字,可以定義類。基本上,ES6的class可以看作只是一個語法糖,它的絕大部分功能,ES5都可以做到,新的class寫法只是讓對象原型的寫法更加清晰、更像面向對象編程的語法而已。上面的代碼用ES6的“類”改寫,就是下面這樣。

//定義類
class Point {
    constructor(x, y) {    //constructor 構造方法 this.x = x;
        this.y = y;
    }

    toString() {
        return '(' + this.x + ', ' + this.y + ')';
    }
}

var p = new Point(1, 2);

  構造函數的prototype屬性,在ES6的“類”上面繼續存在。事實上,類的所有方法都還是定義在類的prototype屬性上面。

 

  2.constructor方法

  constructor方法是類的默認方法,通過new命令生成對象實例時,自動調用該方法。一個類必須有constructor方法,如果沒有顯式定義,一個空的constructor方法會被默認添加。

 

二、繼承(Extends)

  Class之間可以通過extends關鍵字實現繼承,這比ES5的通過修改原型鏈實現繼承,要清晰和方便很多。

class ColorPoint extends Point {
    constructor(x, y, color) {
        super(x, y); // 調用父類的constructor(x, y)
        this.color = color;
    }

    toString() {
        return this.color + ' ' + super.toString(); // 調用父類的toString()
    }
}

  上面代碼中,constructor方法和toString方法之中,都出現了super關鍵字,它在這里表示父類的構造函數,用來新建父類的this對象。

  子類必須在constructor方法中調用super方法,否則新建實例時會報錯。這是因為子類沒有自己的this對象,而是繼承父類的this對象,然后對其進行加工。如果不調用super方法,子類就得不到this對象。

 

三、原生構造函數繼承

  原生構造函數是指語言內置的構造函數,通常用來生成數據結構。ECMAScript的原生構造函數大致有下面這些。以前,這些原生構造函數是無法繼承的。

  • Boolean()
  • Number()
  • String()
  • Array()
  • Date()
  • Function()
  • RegExp()
  • Error()
  • Object()

  ES6允許繼承原生構造函數定義子類,因為ES6是先新建父類的實例對象this,然后再用子類的構造函數修飾this,使得父類的所有行為都可以繼承。下面是一個繼承Array的例子。

class MyArray extends Array {
    constructor(...args) {
        super(...args);
    }
}

var arr = new MyArray();
arr[0] = 12;
arr.length // 1

arr.length = 0;
arr[0] // undefined

  上面代碼定義了一個MyArray類,繼承了Array構造函數,因此就可以從MyArray生成數組的實例。這意味着,ES6可以自定義原生數據結構(比如Array、String等)的子類,這是ES5無法做到的。

 

四、Class的Generator方法

  如果某個方法之前加上星號(*),就表示該方法是一個Generator函數。

class Foo {
    constructor(...args) {
        this.args = args;
    }
    * [Symbol.iterator]() {
        for (let arg of this.args) {
            yield arg;
        }
    }
}

for (let x of new Foo('hello', 'world')) {
    console.log(x);
}
// hello
// world

 

上面代碼中,Foo類的Symbol.iterator方法前有一個星號,表示該方法是一個Generator函數。Symbol.iterator方法返回一個Foo類的默認遍歷器,for...of循環會自動調用這個遍歷器。

 

五、Class的靜態方法

  類相當於實例的原型,所有在類中定義的方法,都會被實例繼承。如果在一個方法前,加上static關鍵字,就表示該方法不會被實例繼承,而是直接通過類來調用,這就稱為“靜態方法”。

class Foo {
    static classMethod() {
        return 'hello';
    }
}

Foo.classMethod() // 'hello'

var foo = new Foo();
foo.classMethod()
// TypeError: foo.classMethod is not a function

  上面代碼中,Foo類的classMethod方法前有static關鍵字,表明該方法是一個靜態方法,可以直接在Foo類上調用(Foo.classMethod()),而不是在Foo類的實例上調用。如果在實例上調用靜態方法,會拋出一個錯誤,表示不存在該方法。

  父類的靜態方法,可以被子類繼承。

class Foo {
    static classMethod() {
        return 'hello';
    }
}

class Bar extends Foo {
}

Bar.classMethod(); // 'hello'

  上面代碼中,父類Foo有一個靜態方法,子類Bar可以調用這個方法。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM