前言
提到ES6中的class你會想到什麼呢?可能有的小夥伴只是知道它,或許用過一兩次,沒關係,這次我們從頭開始,帶你體驗class的鐵漢柔情(強大和優雅);
跟往常一樣,我們需要帶著三個問題去看這篇文章:what?how? where?
什麼是Class
使用react的小夥伴都知道,最初學習使用react框架的時候,首先了解的就是通過class來書寫元件,所以,通過閱讀這篇文章,也是為學習react打一個重要的基礎!讓我們先看一個class標準的寫法吧:
class Point {
constructor (x, y) {
this.x = x
this.y = y
}
MyName () {
return (`我的名字叫${this.x}${this.y}!`)
}
}
let getName = new Point('f', 'zh');
getName.MyName() // 我的名字叫fzh
複製程式碼
通過上面的程式碼可以看出這個class的寫法,與ES5中建構函式的寫法很相似,沒錯,class
就是建構函式的語法糖(可以理解成class
就是建構函式的另一種寫法),使用的時候,也是直接對class
(類)使用new
命令,跟建構函式的用法完全一致;考慮到有的同學不太明白上面寫的啥,在這裡解釋一下:
- 首先宣告瞭一個名字為Point的class,換做ES5的寫法就是
function Point ( ) { }
;class
裡面寫的方法,最終都定義在了class
的原型上,換做ES5的寫法就是:Point.prototype.MyName = function ( ) { }
;constructor
方法就是構造方法,裡面的this
代表例項物件,constructor
屬性,直接指向“類”的本身;constructor
是class的預設方法,通過new
命令生成物件例項時,自動呼叫constructor
,即使沒有定義constructor
,也會預設有一個空的constructor
;
它的絕大部分功能,ES5都可以做到,新的class寫法只是讓物件原型的寫法更加清晰、更像物件導向程式設計的語法而已,光說無用,讓我們來證明一下吧:
// 接上面程式碼
console.log(typeof Point); // "function"
console.log(Point === Point.prototype.constructor); // true
複製程式碼
這段程式碼表明瞭類的資料型別就是函式,類的本身就是指向建構函式;
本段需要注意的地方如下:
- class內部定義的方法都是不可列舉的;
- 生成類的寫法需使用
new
命令,否則會報錯; constructor
方法預設返回例項物件(即this
);- 類和模組的內部,預設就是嚴格模式,所以不需要使用
use strict
指定執行模式; - 類不存在變數提升;
- 類的方法內部如果含有this,它預設指向類的例項;
以上就是class的基本知識,如果理解了上面的內容,那麼恭喜你,可以放心的在你程式碼中使用class了!
class進階知識
開頭我們們說到過class是強大和優雅的,那麼它到底強大在哪?又優雅在哪呢?我怎麼讀現在還沒有看出來呢?好,讓我們帶著這兩個疑問去下面的文章尋找答案!
class靜態方法
類相當於例項的原型,所有在類中定義的方法都會被例項繼承,如果不想讓你定義的方法被例項繼承,也很簡單,只需要在方法前面加上 static
關鍵字,就表示該方法不會被例項繼承,而且直接通過類就可以呼叫,這也稱為 靜態方法 ,看下面程式碼:
class MyStatic {
static classMsg () {
return ("My name is feng zhihao");
}
}
// 因為"classMsg"定義方法名稱之前加了 'static' 關鍵字
// 所以該方法是一個靜態方法
Mystatic.classMsg(); // "My name is feng zhihao"
let foo = new Mystaic();
foo.classMsg(); // TypeError: foo.classMsg is not a function
複製程式碼
上面程式碼表明:靜態方法可以直接在類上呼叫,而不是在類的例項上呼叫,如果在例項上呼叫的話,就會丟擲錯誤,表示不存在該方法;擴充套件一下,父類的靜態方法可以被子類繼承:
class Fzh {
static classMsg () {
return (`新春快樂,鼠你最棒`);
}
}
class Ibas extends Fzh {}
Ibas.classMsg(); // "新春快樂,鼠你最棒"`
複製程式碼
new.target屬性
new
是從建構函式生成例項的命令,ES6為 new
命令引入了 new.target
屬性,如果建構函式不是通過 new
命令呼叫的,那麼 new.target
會返回 undefined
,在 class
內部呼叫 new.target
,返回是當前class,需要注意的是:子類繼承父類時,new.target
會返回子類:
// " 返回當前class "
class Register {
constructor (x) {
console.log(new.target === Register);
this.x = x;
}
}
// 返回的是true,說明new.target返回的是當前的class
let RegClass = new Register("hello") // true
複製程式碼
// "父類呼叫new.target返回子類"
class Register {
constructor () {
console.log(new.target === Register);
}
}
class Square extends Register {
constructor (x) {
super(x, x);
}
}
let sole = new Square(1); // false(new.target返回的是子類)
複製程式碼
super關鍵字
讀到這,是不是覺得初學react的時候就是在學習class呢,尤其是 extends
、super
關鍵字,我們會經常碰到它們的身影,其實super
這個關鍵字既可以當做函式使用,也可以當做物件使用,在這兩種情況下,它的作用完全不同:
第一種情況: 做為函式時,super
只能用在子類的建構函式中,用在其他地方會報錯;當呼叫super時,它代表父類的建構函式 ( 這是規定 ) ,ES6還規定了子類的建構函式必須執行一次super函式;
接下來的說法可能比較繞,建議讀完一遍然後看一遍程式碼,再回過頭讀一遍效果會更好:super雖然代表父類,但是它返回的是子類的例項,也就是說super內部的this是指向子類的,證明一下:
class Supe {
constructor () {
console.log(new.target.name);
}
}
class SonSupe extends Supe {
constructor () {
super();
}
}
new Supe(); // Supe
new SonSupe(); // SonSupe
複製程式碼
從上面程式碼可以看出,new.target指的是當前正在執行的函式,在 super
執行時,它指向的是子類 SonSuper
的建構函式,而不是父類 Supe
的建構函式,也就是說,super()
內部的this是指向子類的。
第二種情況: super作為物件時,在普通方法中指向父類的原型物件,在靜態方法中指向父類,由於 super
指向的是父類的原型物件,所以定義在父類例項上的方法或屬性是無法通過 super
呼叫的:
class A {
gain () {
return ("歡迎大佬指出不足,我絕對不會改~");
}
}
class B extends A {
constructor () {
super();
console.log(super.gain()); // "歡迎大佬指出不足,我絕對不會改~"
}
}
複製程式碼
從上面程式碼可以看出super指向父類的prototype
,所以 super.gain()
等同於 A.prototype.gain()
,ES6規定:通過 super
呼叫父類方法時,super
會繫結子類的 this
;
結尾
這篇文章主要講了ES6中 class
的語法和小細節,我們需要做的就是記住這些知識點,真真正正的去理解它們,不斷的練習與嘗試,日後才能靈活的去運用到開發中,另外,推薦大家去看一下阮一峰出版的《ES6標準入門》這本書,最後祝小夥伴們新春快樂,永無Bug! 哦了,散會!
本人微信: