<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
繼承也是物件導向的特性之一,但是在 ES6 版本之前是沒有 extends 去實現繼承的,我們只能通過 建構函式 和 原型物件 來實現繼承,其中分別為建構函式來繼承屬性,原型物件來繼承方法,這種繼承模式被稱為 組合繼承
在開始講解組合繼承前我們先來了解一下 call() 方法,call() 方法可以改變 this 的指向,也可以呼叫函數等等,最主要的還是其改變指向的作用
語法格式 | call( 目標this指向,引數1,引數2 ......) |
call() 可以拿來直接用來呼叫函數
<script> function eat(){ console.log('我在吃午飯'); } eat.call() </script>
call() 的第一個引數為你要改變的 this 的指向,這裡的 this 指的是 call 的呼叫者,此處函數呼叫不指定的話即指向 window,指定讓其指向新建立的物件 obj,只需要讓其第一個引數為 obj 物件即可,所以結果應該是第一個為 window,第二個為 obj 物件
<script> function eat(){ console.log(this); } var obj={ 'name':'小明', 'age':18 } eat.call() eat.call(obj) </script>
我們已經知道組合繼承是由建構函式和原型物件一起來實現的,其中建構函式實現的是屬性的繼承,原型物件實現的是方法的繼承,這版塊就走進利用父建構函式完成屬性的繼承
其實現非常容易,只需要在子建構函式中,使用 call 呼叫父建構函式(將其當做普通函數呼叫),其中在 call 方法中更改父建構函式中的 this 指向,由於 call 方法是在子建構函式中呼叫的,所以此處當做引數的 this 代表父建構函式中的 this 指向子建構函式的範例化物件,並傳參進去,所以相當於給子建構函式的範例化物件新增了屬性並賦值
<script> //宣告父建構函式 function Father(uname,uage,utel,sex){ this.uname=uname; this.uage=uage; this.utel=utel; this.sex=sex; } //宣告子建構函式,但是想繼承父類別的uname,uage,utel等等屬性的賦值操作 function Son(uname,uage,utel,sex){ Father.call(this,uname,uage,utel,sex) } var son1=new Son('張三',19,12345,'男') console.log(son1); </script>
組合繼承的最後一版塊,利用原型物件來繼承方法,此處我們說明的是存放在建構函式的原型物件裡的公共方法的繼承
錯誤的繼承就是直接將父親的原型物件賦值給子的原型物件,這樣確實也可行,但是如果給子原型物件新增子類特有的方法,那父原型物件也會加上這個方法
<script> //宣告父建構函式 function Father(uname,uage){ this.uname=uname; this.uage=uage; } Father.prototype.money=function(){ console.log('我有很多錢'); } //宣告子建構函式 Son.prototype=Father.prototype; function Son(uname,uage){ Father.call(this,uname,uage) } var father1=new Father('爸爸',40) var son1=new Son('兒子',19) console.log(father1); console.log(son1); </script>
我們可以發現父子的原型物件中確實都有了這個方法,證明確實這個辦法是行得通的
但是其也有問題存在,當我們想給子原型物件單獨新增其特有的方法時,就會出問題
上述問題給子原型物件新增特有方法的錯誤範例:
<script> //宣告父建構函式 function Father(uname,uage){ this.uname=uname; this.uage=uage; } Father.prototype.money=function(){ console.log('我有很多錢'); } //宣告子建構函式 Son.prototype=Father.prototype; Son.prototype.school=function(){ console.log('我去上學了'); } function Son(uname,uage){ Father.call(this,uname,uage) } var father1=new Father('爸爸',40) var son1=new Son('兒子',19) console.log(father1); console.log(son1); </script>
我們發現,我們確實給兒子新增上了兒子特有的方法,但是,父親的原型物件內也加上了這個方法,這並不滿足我們的預期,原因分析如下
問題原因
問題就在於我們的原型物件也是物件,物件是參照資料型別,參照資料型別的物件本質是在堆記憶體存放,是不能直接存取的,其存取是通過棧記憶體上的參照地址來找到去存取,而我們此處採用的等號賦值的方式,實際上是將其在棧記憶體上的參照地址拷貝過去了,二者指向了同一塊記憶體空間,所以更改子原型物件,父原型物件也改變了
正確的做法是讓其子原型物件物件等於父範例化物件 Son.prototype=new Father(),其實我感覺有種高內聚低耦合的韻味,減少了直接聯絡從而解決問題
<script> //宣告父建構函式 function Father(uname,uage){ this.uname=uname; this.uage=uage; } Father.prototype.money=function(){ console.log('我有很多錢'); } //宣告子建構函式 Son.prototype=new Father(); Son.prototype.school=function(){ console.log('我去上學了'); } function Son(uname,uage){ Father.call(this,uname,uage) } var father1=new Father('爸爸',40) var son1=new Son('兒子',19) console.log(father1); console.log(son1); </script>
問題得以解決,子原型物件有了自己特有的方法,並且也繼承了父親原型物件中的方法
我們以 Son.prototype=new Father() 這種方法繼承,看似已經天衣無縫,其實我們早就說過,採用等號賦值的方法會造成原型物件被覆蓋,裡面的建構函式 constructor 會被覆蓋掉,需要我們手動返回,所以七千萬要記得手動返回 constructor
<script> //宣告父建構函式 function Father(uname,uage){ this.uname=uname; this.uage=uage; } Father.prototype.money=function(){ console.log('我有很多錢'); } //宣告子建構函式 Son.prototype=new Father(); Son.prototype.constructor=Son; //手動返回建構函式constructor Son.prototype.school=function(){ console.log('我去上學了'); } function Son(uname,uage){ Father.call(this,uname,uage) } var father1=new Father('爸爸',40) var son1=new Son('兒子',19) console.log(father1); console.log(son1); console.log(Son.prototype.constructor); </script>
補充:缺點
就是 “物件原型繼承的this物件+prototype物件,都在物件的原型上 suber1._ proto _”,suber1._ proto _上的參照屬性任然是共用;
所以就有了我們看到的一句勸告:儘量把屬性定義在建構函式內,為了方便繼承吧;
還有就是範例一個物件,執行了兩次Super()
到此這篇關於JavaScript進階教學之非extends的組合繼承的文章就介紹到這了,更多相關js非extends的組合繼承內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45