無論React還是RN都已經邁入了ES6的時代,甚至憑藉Babel的支援都進入了ES7。ES6內容很多,本文主要講解類相關的內容。

建構函式

定義偵探類作為例子。

ES5的“類”是如何定義的。

function ES5Detective() {
console.log('##ES5Detective contructor');
}

ES6定義類:

class ES6Detective {
constructor() {
console.log('Detective constructor');
}
}

ES6使用了class關鍵字,而且有專門的constructor。ES5裡的function ES5Detective既是類的定義,也是建構函式。

屬性

看看這個偵探是從哪本書出來的。

ES5:

ES5Detective.prototype.fromBookName = 'who';

ES6:

class ES6Detective {
detectiveName: string;
_bookName: string; constructor() {
console.log('Detective constructor');
this.detectiveName = 'Detective who'; // 屬性
}
}

ES6 getter & setter

class ES6Detective {
detectiveName: string;
_bookName: string; constructor() {
console.log('Detective constructor');
this.detectiveName = 'Detective who';
this._bookName = 'who';
} get fromBookName() {
return this._bookName;
} set fromBookName(value) {
this._bookName = value;
}
}

如果只有getter沒有setter而賦值的話就會出現下面的錯誤:

detective.bookAuthor = 'A C';
^ TypeError: Cannot set property bookAuthor of #<ES6Detective> which has only a getter

例項方法

偵探是如何解決案件的。

ES5:

ES5Detective.prototype.solveCase = function(caseName) {
var dn = this.dectiveName;
if(!caseName) {
console.log('SOLVE CASE: ' + dn + ' no case to solve');
} else {
console.log('SOLVE CASE: ' + dn + ' get case ' + caseName + ' is solved');
}
};

或者:

function ES5Detective() {
this.dectiveName = 'Detective who';
console.log('##ES5Detective contructor');
// 例項方法
this.investigate = function(scene) {
console.log('investigate ' + scene);
} this.assistant = "assistant who";
}

ES6:

class ES6Detective {
detectiveName: string;
_bookName: string; constructor() {
console.log('Detective constructor');
this.detectiveName = 'Detective who';
this._bookName = 'who';
} solveCase(caseName) {
if(!caseName) {
console.log('no case to solve');
} else {
console.log('case ' + caseName + ' is solved');
}
}
}

ES6新增方法非常簡單直接。ES5中新增例項方法有兩種方法,一是在prototype裡定義,一是在建構函式重定義。在建構函式中定義的例項方法和屬性在每一個例項中都會保留一份,而在原型中定義的例項方法和屬性是全部例項只有一份

另外,在ES5的建構函式重定義的例項方法可以訪問類的私有變數。比如:

function ES5Detective() {
console.log('##ES5Detective contructor'); var available: boolean = true; // private field. default income is ZERO.
this.investigate = function(scene) {
if (available) {
console.log('investigate ' + scene);
} else {
console.log(`i'm not available`);
}
}
}

在其他的方法訪問的時候就會報錯。

if (!available) {
^

靜態方法

ES5:

ES5Detective.countCases = function(count) {
if(!count) {
console.log('no case solved');
} else {
console.log(`${count} cases are solved`);
}
};

類名後直接定義方法,這個方法就是靜態方法。

ES5Detective.countCases();

ES6:

class ES6Detective {
static countCases() {
console.log(`Counting cases...`);
}
} // call it
ES6Detective.countCases();

繼承

ES6使用extends關鍵字實現繼承。

ES5:

function ES5Detective() {
var available: boolean = true; // private field. this.dectiveName = 'Detective who';
console.log('##ES5Detective contructor'); this.investigate = function(scene) {
// 略
} this.assistant = "assistant who";
} ES5Detective.prototype.solveCase = function(caseName) {
// 略
} // inheritance
function ES5DetectiveConan() {
// first line in constructor method is a must!!!
ES5Detective.call(this); this.dectiveName = 'Conan';
} // inheritance
ES5DetectiveConan.prototype = Object.create(ES5Detective.prototype);
ES5DetectiveConan.prototype.constructor = ES5DetectiveConan;

ES5繼承的時候需要注意兩個地方:

  1. 需要在子類的建構函式裡呼叫SuperClass.call(this[, arg1, arg2, ...])
  2. 子類的prototype賦值為:SubClass.prototype = Object.create(SuperClass.prototype),然後把建構函式重新指向自己的:SubClass.prototpye.constructor = SubClass

ES6:

class ES6Detective {
constructor() {
console.log('Detective constructor');
this.detectiveName = 'Detective who';
this._bookName = 'who';
} solveCase(caseName) {
if(!caseName) {
console.log('no case to solve');
} else {
console.log('case ' + caseName + ' is solved');
}
} get fromBookName() {
return this._bookName;
} set fromBookName(value) {
this._bookName = value;
} get bookAuthor() {
return 'Author Who';
} static countCases() {
console.log(`Counting cases...`);
}
} class ES6DetectiveConan extends ES6Detective {
constructor() {
super();
console.log('ES6DetectiveConan constructor');
}
}

ES6的新語法更加易懂。

注意:一定要在子類的構造方法裡呼叫super()方法。否則報錯。

呼叫super類內容

class ES6DetectiveConan extends ES6Detective {
constructor() {
super();
console.log('ES6DetectiveConan constructor');
} solveCase(caseName) {
super.solveCase(caseName); if(!caseName) {
console.log('CONAN no case to solve');
} else {
console.log('CONAN case ' + caseName + ' is solved');
}
}
}

靜態方法可以被繼承

ES6的靜態方法可以被繼承。ES5的不可以。

class ES6Detective {
static countCases(place) {
let p = !place ? '[maybe]' : place;
console.log(`Counting cases...solve in ${p}`);
}
} class ES6DetectiveConan extends ES6Detective {
constructor() {
super();
console.log('ES6DetectiveConan constructor');
}
} // static method
ES6Detective.countCases();
ES6DetectiveConan.countCases('Japan'); // result
Counting cases...solve in [maybe]
Counting cases...solve in Japan

在子類ES6DetectiveConan並沒有定義任何方法,包括靜態方法。但是,在父類和子類裡都可以呼叫該方法。

甚至,可以在子類裡呼叫父類的靜態方法:

class ES6DetectiveConan extends ES6Detective {
static countCases(place) {
let p = !place ? '[maybe]' : place;
super.countCases(p);
console.log(`#Sub class:- Counting cases...solve in ${p}`);
}
} // result
Counting cases...solve in [maybe]
Counting cases...solve in Japan
#Sub class:- Counting cases...solve in Japan

程式碼

https://github.com/future-challenger/ES-Samples/tree/master/class