React Native填坑之旅--class(番外篇)
無論React還是RN都已經(jīng)邁入了ES6的時代,甚至憑借Babel的支持都進入了ES7。ES6內(nèi)容很多,本文主要講解類相關(guān)的內(nèi)容。
構(gòu)造函數(shù)
定義偵探類作為例子。
ES5的“類”是如何定義的。
- function ES5Detective() {
- console.log('##ES5Detective contructor');
- }
ES6定義類:
- class ES6Detective {
- constructor() {
- console.log('Detective constructor');
- }
- }
ES6使用了class關(guān)鍵字,而且有專門的constructor。ES5里的function ES5Detective既是類的定義,也是構(gòu)造函數(shù)。
屬性
看看這個偵探是從哪本書出來的。
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;
- }
- }
如果只有g(shù)etter沒有setter而賦值的話就會出現(xiàn)下面的錯誤:
- 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里定義,一是在構(gòu)造函數(shù)重定義。在構(gòu)造函數(shù)中定義的實例方法和屬性在每一個實例中都會保留一份,而在原型中定義的實例方法和屬性是全部實例只有一份。
另外,在ES5的構(gòu)造函數(shù)重定義的實例方法可以訪問類的私有變量。比如:
- 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) {
- ^
靜態(tài)方法
ES5:
- ES5Detective.countCases = function(count) {
- if(!count) {
- console.log('no case solved');
- } else {
- console.log(`${count} cases are solved`);
- }
- };
類名后直接定義方法,這個方法就是靜態(tài)方法。
- ES5Detective.countCases();
ES6:
- class ES6Detective {
- static countCases() {
- console.log(`Counting cases...`);
- }
- }
- // call it
- ES6Detective.countCases();
繼承
ES6使用extends關(guān)鍵字實現(xiàn)繼承。
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繼承的時候需要注意兩個地方:
- 需要在子類的構(gòu)造函數(shù)里調(diào)用SuperClass.call(this[, arg1, arg2, ...])
- 子類的prototype賦值為:SubClass.prototype = Object.create(SuperClass.prototype),然后把構(gòu)造函數(shù)重新指向自己的: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的新語法更加易懂。
注意:一定要在子類的構(gòu)造方法里調(diào)用super()方法。否則報錯。
調(diào)用super類內(nèi)容
- 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');
- }
- }
- }
靜態(tài)方法可以被繼承
ES6的靜態(tài)方法可以被繼承。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并沒有定義任何方法,包括靜態(tài)方法。但是,在父類和子類里都可以調(diào)用該方法。
甚至,可以在子類里調(diào)用父類的靜態(tài)方法:
- 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
代碼