天天看點

ES6學習-Class和Class的繼承

說明:本文參考阮一峰的ECMAScript 6 入門

1.Class

類的由來

JavaScript語言中,生成執行個體對象的傳統方法是通過構造函數。

function Person (name, age) {
	this.name = name
	this.age = age
}
Person.prototype.toString = function () {
	return `${name},${age}`
}

var per = new Person("wangwu", 19)
           

上面這種寫法跟面向對象語言(C++、Java)差異很大,很容易讓學習這門語言的程式員感到困惑。

ES6提供了更接近傳統語言的寫法,引入了class(類)這個概念,作為對象的模闆。通過class關鍵字可以定義類。

新的Class寫法隻是讓對象原型的寫法更加清晰、更加面向對象程式設計的文法而已。上面代碼用ES6的class寫法,就是下面這樣。

calss Person {
	constructor(name, age){
		this.name = name
		this.age = age
	}
	toString() {
		return `${this.name},${this.age}`
	}
}
var per = new Person("wangwu", 19)
           

上面代碼,定義了一個類,裡面有一個constructor方法,這就是構造方法,this代表執行個體對象。構造執行個體的時候,也是直接對類使用new指令,跟構造函數的用法完全一緻。

Person類還定義了一個toString方法。注意,定義類的方法時候,不需要在前面加上關鍵字function,直接把函數定義放進去就可以了。另外方法之間,不需要逗号分隔,加了逗号會報錯。

ES6的類可以看作構造函數的另一種寫法。

class Person {

}
typeof Person //function
Person === Point.prototype.constructor //true
           

上面代碼說明,類的資料類型就是函數,類本身指向構造函數。類的所有方法都是定義在類的prototype屬性上面。在類的執行個體上調用方法就是調用原型上的方法。

另外,類的内部所有定義的方法,都是不可枚舉的(non-enumerable)。

注意點

  1. 嚴格模式,類和子產品的内部,預設就是嚴格模式。考慮到未來所有的代碼,其實都是運作在子產品之中,是以 ES6 實際上把整個語言更新到了嚴格模式。
  2. 不存在提升,類不存在變量提升(hoist)。
  3. this指向,類的方法内部如果含有this,它預設指向類的執行個體。
  4. 靜态方法,如果在一個方法前,加上static關鍵字,就表示該方法不會被執行個體繼承,而是直接通過類來調用,這就稱為“靜态方法”。如果靜态方法包含this關鍵字,這個this指的是類,而不是執行個體。

2.CLass的繼承

class是通過extends關鍵字來繼承的,這比 ES5 的通過修改原型鍊實作繼承,要清晰和友善很多。

class Person {

}

class Student extends Person {

}
           

上面代碼定義了一個Student類,該類通過extends關鍵字繼承了Person類的所有屬性和方法。

類的prototyppe屬性和__proto__屬性

大多數浏覽器ES5實作之中,每一個對象都有__proto__屬性,指向對應的構造函數的prototype屬性。Class作為構造函數的文法糖,同時有prototype屬性和__proto__屬性。是以具有兩條繼承鍊。

(1)子類的__proto__屬性,表示構造函數的繼承,總是指向父類。

(2)子類的prototype的__proto__屬性,表示方法的繼承,總是指向父類的prototype屬性。

class A {

}

class B extends A {
	
}

B.__proto__ === A //true
B.prototype.__proto__ === A.prototype
           

上面代碼中,子類B的__proto__屬性指向父類A,子類B的prototype屬性的__proto__屬性指向父類A的prototype屬性。

這樣的結果是因為,類的繼承是按照下面的模式實作的。

class A {
}

class B {
}

// B 的執行個體繼承 A 的執行個體
Object.setPrototypeOf(B.prototype, A.prototype);

// B 繼承 A 的靜态屬性
Object.setPrototypeOf(B, A);

const b = new B();
           

下面這段代碼是Object.setPrototypeOf方法的實作。

Object.setPrototypeOf = function (obj, proto) {
  obj.__proto__ = proto;
  return obj;
}
           

是以,就得到了上面的結果。

繼續閱讀