原生Javascript實現(xiàn)繼承方式及其優(yōu)缺點詳解
前言
最近在復習javascript的一些基礎知識,為開啟新的征程做準備。所以開始記錄一些自己學習的內(nèi)容。
那今天的主題是 js的原生繼承方式
廢話少說,上代碼!
首先是我們的父類代碼。
在這里我們創(chuàng)建一個Person的類作為父類,它的構造函數(shù)需要2個參數(shù)name和age。
然后我們在它的原型上添加一個sayHi的方法。
//父類 function Person (name, age) { this.name = name || 'no name'; this.age = age || 0; } Person.prototype.sayHi = function () { console.log('Hi, I\'m ' + this.name + ' and i\'m ' + this.age + ' years old!'); } var p = new Person('A',20); p.sayHi();//Hi, I'm A and i'm 20 years old!
原型繼承
//原型繼承 function Teacher(){ } Teacher.prototype=new Person('B',22); Teacher.prototype.constructor=Teacher; var t = new Teacher(); t.sayHi();//Hi, I'm B and i'm 22 years old! console.log(t instanceof Person);//true console.log(t instanceof Teacher);//true
優(yōu)點
從上面的代碼來看,Teacher 的實例擁有了 Person 的屬性和方法。并且實例對象既是 Person的實例也是 Teacher的實例。而且這種繼承方式特別的簡單。
缺點
我們可以很容易的就發(fā)現(xiàn)Teacher類的 name和 age是固定的,都是name=B和age=22,換句話說就是我們無法實現(xiàn)按照我們的意愿給父類的構造函數(shù)傳參。并且一個我們不能給一個 Teacher 指定多個原型,也就是沒法 多繼承。然后我們看下下面這段代碼:
var t1 = new Teacher(); var t2 = new Teacher(); Teacher.prototype.name = "C"; t1.sayHi();//Hi, I'm C and i'm 22 years old! t2.sayHi();//Hi, I'm C and i'm 22 years old!
上面這段代碼中我們可以看到當原型中的屬性或者方法被改變時,所有的子類實例的屬性和方法也會跟著被改變,也就是原型繼承的另一個缺點:所有子類共享同一個原型對象
這里說到了原型,我很早之前也寫過一個關于原型的隨筆,不過可能也是有些模糊,現(xiàn)在的理解和當時有所不同,我會在后面重新寫一篇關于原型的隨筆。(寫好了我會附上連接)
構造函數(shù)繼承
//構造函數(shù)繼承 function Teacher (name, age) { Person.call(this, name, age); } var t1 = new Teacher('B', 22); var t2 = new Teacher('C', 30); console.log(t1.name);//B console.log(t2.name);//C console.log(t1 instanceof Person);//false console.log(t1 instanceof Teacher);//true t1.sayHi();//TypeError: t1.sayHi is not a function t2.sayHi();//TypeError: t1.sayHi is not a function
優(yōu)點
相對于 原型繼承 , 構造函數(shù)繼承解決了所有的子類實例共享統(tǒng)一原型的問題,也可以給父類的構造函數(shù)傳參,并且我們可以在子類的構造函數(shù)中調用多個父類的構造函數(shù),實現(xiàn)所謂的多繼承(這里的多繼承是指子類通過call,apply等方法去調用父類的構造函數(shù)使其擁有父類的屬性和方法,但是js中一個函數(shù)對象只存在一個 prototype,所以其實我們沒法通過原型鏈的形式去體現(xiàn)出多繼承)
缺點
上面的代碼中我們可以看出創(chuàng)建的實例只是 子類的實例 并不是 父類的實例 ,不能直觀的體現(xiàn)出繼承,這種繼承方式也無法繼承父類的原型上的屬性和方法。
組合式繼承
//組合式繼承 function Teacher (name, age) { Person.call(this, name, age); } Teacher.prototype = new Person(); Teacher.prototype.constructor = Teacher; var t1 = new Teacher('B', 22); var t2 = new Teacher('C', 30); Teacher.prototype.name = "D"; console.log(t1.name);//B console.log(t2.name);//C t1.sayHi();//Hi, I'm B and i'm 22 years old! t2.sayHi();//Hi, I'm C and i'm 30 years old! console.log(t1 instanceof Person);//true console.log(t1 instanceof Teacher);//true
組合式繼承就是結合了原型繼承和構造函數(shù)繼承的優(yōu)點,解決了兩種方式存在的一些缺點。但是我們會發(fā)現(xiàn)每當我們?nèi)?chuàng)建一個子類實例的時候都會去創(chuàng)建一個父類的實例,盡管父類實例不是同一個實例(內(nèi)存地址不一樣),但是他們其實屬性和方法上完全一致,所以我們通過下面這種(寄生式組合繼承)方式完善它,以避免不必要的實例構造。
寄生式組合繼承
//寄生式組合繼承 function Teacher (name, age) { Person.call(this, name, age); } Teacher.prototype = Object.create(Person.prototype); Teacher.prototype.constructor = Teacher; var t1 = new Teacher('B', 22); var t2 = new Teacher('C', 30); Teacher.prototype.name = "D"; console.log(t1.name);//B console.log(t2.name);//C t1.sayHi();//Hi, I'm B and i'm 22 years old! t2.sayHi();//Hi, I'm C and i'm 30 years old! console.log(t1 instanceof Person);//true console.log(t1 instanceof Teacher);//true
上面的方式解決了我們沒創(chuàng)建一個子類實例都去創(chuàng)建一個父類實例的問題,這也是最為常用的一種js的繼承方式,如果我們通過Babel去把ES6中的class的繼承轉成ES5的代碼,我們會發(fā)現(xiàn)就是用的寄生式組合繼承。
總結
到此這篇關于原生Javascript實現(xiàn)繼承方式及其優(yōu)缺點的文章就介紹到這了,更多相關原生Javascript繼承方式內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
javascript 讀取XML數(shù)據(jù),在頁面中展現(xiàn)、編輯、保存的實現(xiàn)
最近需要做這樣一個需求,數(shù)據(jù)保存在XML里,在頁面上通過表格顯示其內(nèi)容,可以修改內(nèi)容,再保存到XML。下面把做這個東西的過程記錄下來,做個筆記,也給需要的人一些幫助。2009-10-10ff chrome和ie下全局動態(tài)定位的異同及全局高度的取法
這篇文章主要介紹了ff chrome和ie下全局動態(tài)定位的異同及全局高度的取法,需要的朋友可以參考下2014-06-06