本文是 ES6
系列的第四篇,能夠在 這裏 查看 往期全部內容git
這篇文章主要記錄了一些 class
相關的內容,都是咱們平常開發中可能會遇到的知識點es6
若是文章中有出現紕漏、錯誤之處,還請看到的小夥伴多多指教,先行謝過github
如下↓web
ES6
以前,咱們生成實例對象的方法都是經過構造函數編程
function Person(name) { this.name = name } Person.prototype.say = function() { console.log(this.name) } var p = new Person('遊蕩de蝌蚪')
ES6
引入了 類
的概念,經過 class
關鍵字來定義。上面的代碼就能夠這樣改寫segmentfault
class Person { constructor(name) { this.name = name } say() { console.log(this.name) } } let p = new Person('遊蕩de蝌蚪')
class
的這種寫法更接近傳統語言,不管是對某個屬性設置存儲函數和取值函數,仍是實現繼承,都要更加清晰和方便微信
類的本質是一個函數,類自身指向的就是構造函數
class Person {} typeof Person // function Person.prototype.constructor == Person // true
ES6
的 class
能夠看做只是一個語法糖,它的絕大部分功能,ES5
均可以作到,新的 class
寫法只是讓對象原型的寫法更加清晰、更像面向對象編程的語法babel
類的構造方法 constructor
對應的就是構造函數,定義在類中的方法都定義在類的 prototype
屬性上面函數
class Person { constructor(){}, say() {}, run() {} ... } // 等同於 Person.prototype = { constructor(){}, say(){}, run(){} ... } let p = new Person() p.say == Person.prototype.say // true
console.log(Person) class Person {} // Uncaught ReferenceError: // Cannot access 'Person' before initialization
let Person = {} class Person {} // Uncaught SyntaxError: // Identifier 'Person' has already been declared
constructor
是類的默認方法,就算不定義,也會默認添加一個空的 constructor
new
關鍵字初始化,不然會報錯class Person {} let p1 = new Person() let p2 = new Person() p1.__proto__ == p2.__proto__ //true
prototype
默認不可重寫class Person {} Object.getOwnPropertyDescriptor(Person, 'prototype') /* configurable: false enumerable: false value: {constructor: ƒ} writable: false */
class Person { static say() { console.log('Hello') } }
class
中若是一個方法前添加了 static
關鍵字,那麼就表示這個方法是靜態方法。它不能被實例繼承,只能經過類來調用學習
let p = new Person() p.say() // Uncaught TypeError: p.say is not a function Person.say() // Hello
須要注意的是:父類的靜態方法,能夠被子類繼承
class Tadpole extends Person {} Tadpole.say() // Hello
所謂靜態屬性,就是類自己的屬性,也就是說屬性不能經過添加在 this
上的方式定義
// 屬性不能定義在 this 上面,會被實例繼承 class Person { constructor(name) { this.name = name } }
ES6
明確規定,Class
內部只有靜態方法,沒有靜態屬性
通常狀況下,咱們實現靜態屬性的方式就是直接將屬性添加到類上面:
Person.age = 18
可也以用一種變通的方式實現:
// 經過 static 靜態方法與 get 方式的結合 class Person { static get age() { return 18 } }
類的靜態屬性和靜態方法的表現基本一致:不能被實例繼承,只能經過類來使用
提案 提供了一種類靜態屬性的另外一種方式,也是使用 static
關鍵字
class Person { static name = 18 }
所謂私有,通常須要具有如下特徵:
class
內部訪問,不能在外部使用ES6
並無提供 class
的私有屬性及方法的實現方式,可是咱們能夠經過如下幾種方式來約定
_
,可是這種方式不是很保險,由於在類的外部仍是能夠訪問到這個方法class Person { // 公有方法 fn(age) { this.age = age } // 私有方法 _foo(age){ return this.age = age } }
this
創造出一個相對封閉的空間class Person{ foo(age) { bar.call(this, age) } } function bar(age) { return this.age = age }
提案 提供了一種實現 class
私有屬性的方式:使用 #
關鍵字
class Person { #age = 18 }
若是咱們在外部使用這個屬性就會報錯
let p = new Person() Person.#age p.#age // Uncaught SyntaxError: // Private field '#age' must be declared in an enclosing class
另外,私有屬性也支持 getter
和 setter
的方式以及靜態 static
的方式
class Person { #age = 18 get #x() { return #age } set #x(value) { this.#age = value } static #say() { console.log(#age) } }
在 class
出現以前,咱們通常都會使用原型以及構造函數的方式實現繼承,更多實現繼承的方式參考 JavaScript中的繼承
類的繼承也是經過原型實現的
ES5
的繼承,實質是先創造子類的實例對象this
,而後再將父類的方法添加到this
上面
ES6
的繼承,實質是先將父類實例對象的屬性和方法,加到this
上面(因此必須先調用super
方法),而後再用子類的構造函數修改this
class
經過extends
關鍵字實現繼承
經過 extends
關鍵字,子類將繼承父類的全部屬性和方法
class Person {} class Tadpole extends Person {}
extends
關鍵字後面不只能夠跟類,也能夠是表達式
function Person(){ return class { say(){ alert('Hello') } } } class Tadpole extends Person(){} new Tadpole().say() // Hello
extends
關鍵字後面還能夠跟任何具備 prototype
屬性的函數(這個特性可讓咱們很輕鬆的複製一個原生構造函數,好比 Object
)
function Fn() { this.name = 'tadpole' } // 注意,這裏 constructor 的指向變了 Fn.prototype = { say() { console.log('My name is tadpole') } } class Tadpole extends Fn {} let t = new Tadpole() t.name // tadpole t.say() // My name is tadpole
子類經過繼承會獲取父類的全部屬性和方法,因此下面的寫法能夠獲得正確的結果
class Person { constructor() { this.name = '遊蕩de蝌蚪' } } class Tadpole extends Person{} let t = new Tadpole() t.name // 遊蕩de蝌蚪
可是,若是咱們在子類中定義了 constructor
屬性,結果就是報錯
class Tadpole extends Person { constructor(){} } let t = new Tadpole() // Must call super constructor in derived class before accessing 'this' or returning from derived constructor
若是咱們想要在子類中定義 constructor
屬性,那麼就必須調用 super
方法
// 正常 class Tadpole extends Person { constructor(){ super() } } let t = new Tadpole()
super表明了父類的構造函數,返回的是子類的實例,至關於 Person.prototype.constructor.call(this)
因此,上面代碼中 super()
的做用實際上就是將 this
添加到當前類,而且返回
super
有兩種使用方式:
super()
只能用在子類的構造函數之中,用在其餘地方就會報錯
super
指向父類的原型對象,因此定義在父類實例上的方法或屬性,沒法經過 super
調用)class Person { constructor() { this.name = '遊蕩de蝌蚪' } say() { console.log('My name is' + this.name) } } class Tadpole extends Person { constructor() { super() console.log(super.say()) // My name is 遊蕩de蝌蚪 console.log(super.name) // undefined } }
class Person { constructor() { this.name = '遊蕩de蝌蚪' } say() { console.log('My name is' + this.name) } static say() { console.log('My name in tadpole') } } class Tadpole extends Person { static say() { super.say() } say() { super.say() } } Person.say() // My name is tadpole Tadpole.say() // My name is tadpole let t = new Tadpole() t.say() // My name is 遊蕩de蝌蚪
this
,默認指向類的實例class Person { say() { this.run() } run() { console.log('Run!') } }
this
關鍵字,這個 this
指的是類,而不是實例class Person { static say() { console.log(this) // Person } }
constructor
中調用 super()
以後才能使用 this
class
中默認使用嚴格模式,若是將其中的方法單獨調用,那麼方法中的 this
指向 undefined
(默認指向全局對象)class
的出現爲咱們的編程提供了不少便利,可是 class
自己也存在一些問題
class
,居然還只是 語法糖
,你說氣人不氣人prototype
,因此 class
也存在原型所具備的一些問題,好比修改父類上面的屬性可能會影響到全部子類(固然,私有屬性的出現仍是解決了一些問題)class
,好比那個啥啥啥,固然了也有解決的方式:babel
儘管 class
仍是存在些許問題,但它必定會愈來愈豐富...
以上就是關於 class
的所有內容,但願對看到的小夥伴有些許幫助
大膽地在你的項目中使用 class
吧,相信你絕對會愛上它
感興趣的小夥伴能夠 點擊這裏 ,也能夠掃描下方二維碼關注個人微信公衆號,查看往期更多內容,歡迎 star
關注