javascript
详解JavaScript中ES5和ES6的类、继承之间区别和联系
導(dǎo)讀: 很多JavaScript的初學(xué)者(比如說我)在剛開始學(xué)習(xí)這門語言的時候,往往會對函數(shù)、對象、類、繼承這些概念感到迷茫和疑惑,感覺他們彼此之間長得十分相似,這就導(dǎo)致很難分清他們什么時候該怎么用。特別是JavaScript中有了原型這個概念之后,就覺得更加混亂了。本篇文章我就從一個初學(xué)者的角度身份來去梳理一下這些概念和用法之間的區(qū)別與聯(lián)系,力圖能讓同樣是初學(xué)者的你很好的分清這些概念之間的用法。
ES5中類、對象和原型
ES5沒有真正定義類的關(guān)鍵字,它通過函數(shù)首字母大寫的方式來告訴別人這是一個類,看起來是比較詭異的。比如下面代碼:
function People(name, age) {// 實例屬性this.name = namethis.age = age }// 類實例化對象 let xiaoming = new People('xiaoming', 22)我們接下來舉例子都是用People這個類來舉例子,具體實例化對象會是某一個person對象。如同上面代碼所示,我們通過首字母大寫的方式定義一個類(或者說告訴大家,這不是一個普通函數(shù),這是一個類),如果寫成函數(shù)的話,要首字母小寫,也就是寫成people的形式。但這樣的話,就很容易混淆了,前面用function定義的話,這到底是函數(shù)還是類呢?判斷是類還是函數(shù)的關(guān)鍵在于new這個關(guān)鍵字。如果通過new賦值的話,就是一個類,并實例化對象。如果沒有的話,就算是一個函數(shù)。至于是不是首字母大寫,不是重點。我們來看下面一個例子。
function People() {console.log('我的名字是小明') }People()這樣的語句就會直接執(zhí)行函數(shù),這就是類和函數(shù)之間的區(qū)別,在于關(guān)鍵字new而不是是否首字母大寫,我們一般約定,首字母大寫的是類。
ES5中也沒有構(gòu)造函數(shù)的關(guān)鍵字。構(gòu)造函數(shù)可以理解為,類在實例化對象時所傳的最初的參數(shù),讓每一個對象具有各自不同的特點。比如我們最初的這個代碼:
function People(name, age) {// 實例屬性this.name = namethis.age = age }// 類實例化對象 let xiaoming = new People('xiaoming', 22)我們可以傳遞xiaoming也可以傳遞xiaoli,這樣就會聲明兩個不同的實例化對象。我們通過的是this關(guān)鍵字來實現(xiàn)構(gòu)造函數(shù)的功能。this表示對于當(dāng)前對象的引用。我們沒有構(gòu)造函數(shù)關(guān)鍵字的話,People既算是一個類,同時也擔(dān)負(fù)起了類中構(gòu)造函數(shù)的責(zé)任。
我們演示完在類中如何添加屬性之后,下面看看如何在類中添加方法。方法和函數(shù)也是容易混淆的概念,具體實現(xiàn)的話功能基本上是一樣的。就是定義的地方不同而已。如果不在類中去定義,我們稱之為函數(shù),如果定義在類里面稱之為類的方法。實例化對象之后,對象還可以調(diào)用方法。
在類中定義方式,使用的是原型。原型是一個稱之為prototype的屬性,這個屬性是一個對象。在它上面定義的屬性和方法,可以被實例化的對象所共享,我們可以將方法定義在類的原型上,這樣實例化對象時,實例化的對象也可以調(diào)用對應(yīng)的方法了。我們一起來看一下代碼:
function People(name, age) {this.name = namethis.age = age }// 實例方法 People.prototype.showName = function () {console.log('我的名字是' + this.name) }let xiaoming = new People('xiaoming', 22) xiaoming.showName()
從圖中可以看出__proto__下面掛載了showName()方法。
ES5中靜態(tài)屬性和靜態(tài)方法
我解釋完這些之后,你可能還有一個疑惑,你說類可以實例化對象,而且類要大寫。那為什么我見到有代碼可以寫成如Math.random()這樣呢?按照這個之前講解的規(guī)則,它好像沒有實例化對象吧。是這樣的,這個稱之為靜態(tài)方法,與之對應(yīng)的還有一個靜態(tài)屬性。不需要將定義的類實例化對象就可以調(diào)用他們。
// 靜態(tài)屬性 People.count = 0// 靜態(tài)方法 People.getCount = function(){console.log(this.age) // undefinedconsole.log('當(dāng)前共有' + People.count + '個人') }這樣就可以像Math.random()一樣,直接調(diào)用靜態(tài)屬性和靜態(tài)方法了。
ES5中的繼承
// 父類 function Animal(name) {this.name = name }// 子類 function Dog(name, color) {// call的作用是用于改變this指向,傳入得第一個參數(shù)用于表示指向誰// 這里用于指向Dog(傳入得是指向Dog的this)// 第二個參數(shù)是Anmial中所對應(yīng)的參數(shù)Animal.call(this, name) // 繼承屬性// 自己個性化的屬性this.color = color }let d1 = new Dog('wangcai', 'white')但是需要注意的是,寫成這樣的形式只能繼承父類的屬性,并不能繼承父類的方法。如果想要繼承父類的方法,需要寫成這樣的形式:
// 父類 function Animal(name) {this.name = name } Animal.prototype.showName = function () {console.log('名字是:' + this.name) }// 子類 function Dog(name, color) {// call的作用是用于改變this指向,傳入得第一個參數(shù)用于表示指向誰// 這里用于指向Dog(傳入得是指向Dog的this)// 第二個參數(shù)是Anmial中所對應(yīng)的參數(shù)Animal.call(this, name) // 繼承屬性// 自己個性化的屬性this.color = color } // 原型繼承 Dog.prototype = new Animal() Dog.prototype.constuctor = Doglet d1 = new Dog('wangcai', 'white') d1.showName()這種繼承稱之為組合繼承,結(jié)合了原型繼承的和構(gòu)造函數(shù)繼承。不過可以看到,這樣寫起來真的比較難以理解。在ES6中,我們引入了很多新的關(guān)鍵字,代碼寫起來要更優(yōu)雅,下面我們一起來看一下在ES6中如何實現(xiàn)這一點。
ES6中類、對象和繼承
class People {constructor(name, age) {this.name = namethis.age = age}showName() {console.log('我的名字是' + this.name)}// 靜態(tài)方法static getCount() {console.log('當(dāng)前共有' + People.count + '個人')} }People.count = 1 let xiaoming = new People('xiaoming', 22) xiaoming.showName()我們看到有新的關(guān)鍵字class用于聲明這是一個類,新的關(guān)鍵字constructor用于聲明構(gòu)造函數(shù),新的關(guān)鍵字static用于聲明靜態(tài)方法。靜態(tài)屬性的話,同樣是不能寫在類里面,要寫在外面,而且同樣靜態(tài)屬性和靜態(tài)方法不能被實例化對象所調(diào)用,只能被類所調(diào)用。
雖然ES6中的類實現(xiàn)是一種基于原型的語法糖形式,但看起來要比ES5的寫法容易理解多了。下面我們再來看一下類的繼承。
class Animal {constructor(name) {this.name = name}showName() {console.log('名字是:' + this.name)} }class Dog extends Animal{constructor(name, color) {super(name)this.color = color}showColor() {console.log('顏色是' + this.color)} }let xiaohua = new Dog('xiaohua', 'white') xiaohua.showName() xiaohua.showColor()在ES6中引入了兩個新的關(guān)鍵字來實現(xiàn)繼承,分別是extends用來繼承父類的方法,和super用來讓子類繼承父類中構(gòu)造函數(shù)的屬性。
總結(jié)
以上是生活随笔為你收集整理的详解JavaScript中ES5和ES6的类、继承之间区别和联系的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 通俗易懂讲解JavaScript深拷贝和
- 下一篇: 写给初学者的JavaScript异步编程