本文是 ES6
系列的第四篇,能夠在 這裏 查看 往期全部內容javascript
這篇文章主要記錄了一些 class
相關的內容,都是咱們平常開發中可能會遇到的知識點java
若是文章中有出現紕漏、錯誤之處,還請看到的小夥伴多多指教,先行謝過git
如下↓es6
ES6
以前,咱們生成實例對象的方法都是經過構造函數github
function Person(name) {
this.name = name
}
Person.prototype.say = function() {
console.log(this.name)
}
var p = new Person('遊蕩de蝌蚪')
複製代碼
ES6
引入了 類
的概念,經過 class
關鍵字來定義。上面的代碼就能夠這樣改寫web
class Person {
constructor(name) {
this.name = name
}
say() {
console.log(this.name)
}
}
let p = new Person('遊蕩de蝌蚪')
複製代碼
class
的這種寫法更接近傳統語言,不管是對某個屬性設置存儲函數和取值函數,仍是實現繼承,都要更加清晰和方便編程
類的本質是一個函數,類自身指向的就是構造函數segmentfault
class Person {}
typeof Person // function
Person.prototype.constructor == Person // true
複製代碼
ES6
的 class
能夠看做只是一個語法糖,它的絕大部分功能,ES5
均可以作到,新的 class
寫法只是讓對象原型的寫法更加清晰、更像面向對象編程的語法微信
類的構造方法 constructor
對應的就是構造函數,定義在類中的方法都定義在類的 prototype
屬性上面babel
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
關注