摘要:一何為繼承繼承,是子類繼承父類的特征和行為,使得子類對(duì)象具有父類的實(shí)例域和方法。目的是通過繼承該父類,產(chǎn)出計(jì)算機(jī)子類。將父類的原型傳遞給子類使用操作符對(duì)父類進(jìn)行實(shí)例化并將實(shí)例對(duì)象賦值給子類的。
本文講述JavaScript中類繼承的實(shí)現(xiàn)方式,并比較實(shí)現(xiàn)方式的差異。一、何為繼承
繼承,是子類繼承父類的特征和行為,使得子類對(duì)象具有父類的實(shí)例域和方法。
繼承是面向?qū)ο缶幊讨校豢苫蛉钡囊徊糠帧?/pre> 1.1 優(yōu)點(diǎn)減少代碼冗余 父類可以為子類提供通用的屬性,而不必因?yàn)樵黾庸δ?,而逐個(gè)修改子類的屬性
代碼復(fù)用 同上
代碼易于管理和擴(kuò)展 子類在父類基礎(chǔ)上,可以實(shí)現(xiàn)自己的獨(dú)特功能
1.2 缺點(diǎn)耦合度高 如果修改父類代碼,將影響所有繼承于它的子類
影響性能 子類繼承于父類的數(shù)據(jù)成員,有些是沒有使用價(jià)值的。但是,在實(shí)例化的時(shí)候,已經(jīng)分配了內(nèi)存。所以,在一定程度上影響程序性能。
二、例子例子以圖書館中的書入庫(kù)歸類為例。
以下是簡(jiǎn)化后的父類Book(也可稱為基類)。
目的是通過繼承該父類,產(chǎn)出Computer(計(jì)算機(jī))子類。
并且,子類擁有新方法say,輸出自己的書名。function Book(){ this.name = ""; // 書名 this.page = 0; // 頁(yè)數(shù) this.classify = ""; // 類型 } Book.prototype = { constructor: Book, init: function(option){ this.name = option.name || ""; this.page = option.page || 0; this.classify = option.classify || ""; }, getName: function(){ console.log(this.name); }, getPage: function(){ console.log(this.page); }, getClassify: function(){ console.log(this.classify); } };接下來會(huì)講解子類Computer幾種繼承方式的實(shí)現(xiàn)和優(yōu)化方法。開始飆車~
三、實(shí)例式繼承function Computer(){ Book.apply(this, arguments); } Computer.prototype = new Book(); Computer.prototype.constructor = Computer; Computer.prototype.init = function(option){ option.classify = "computer"; Book.prototype.init.call(this, option); }; Computer.prototype.say = function(){ console.log("I"m "+ this.name); }3.1 調(diào)用父類構(gòu)造器進(jìn)行初始化function Computer(){ Book.apply(this, arguments); }Computer的構(gòu)造函數(shù)里,調(diào)用父類的構(gòu)造函數(shù)進(jìn)行初始化操作。使子類擁有父類一樣的初始化屬性。
3.2 將父類的原型傳遞給子類Computer.prototype = new Book();使用new操作符對(duì)父類Book進(jìn)行實(shí)例化,并將實(shí)例對(duì)象賦值給子類的prototype。
3.3 缺點(diǎn)
這樣,子類Computer就可以通過原型鏈訪問到父類的屬性。
父類Book的構(gòu)造函數(shù)被執(zhí)行了2次
一次是在Computer的構(gòu)造函數(shù)里Book.apply(this, arguments);
一次是在Computer.prototype = new Book();
這種模式,存在一定的性能浪費(fèi)。
父類實(shí)例化無法傳參
Computer.prototype = new Book();,這種實(shí)例化方式,無法讓Book父類接收不固定的參數(shù)集合。
四、原型式繼承function Computer(){ Book.apply(this, arguments); } Computer.prototype = Object.create(Book.prototype); Computer.prototype.constructor = Computer; Computer.prototype.init = function(option){ option.classify = "computer"; Book.prototype.init(option); }; Computer.prototype.say = function(){ console.log("I"m "+ this.name); }這里的改進(jìn):是使用Object.create(Book.prototype)。它的作用是返回一個(gè)繼承自原型對(duì)象Book.prototype的新對(duì)象。且該對(duì)象下的屬性已經(jīng)初始化。
五、Object.create的簡(jiǎn)單版兼容
用Object.create生成新對(duì)象,并不會(huì)調(diào)用到Book的構(gòu)造函數(shù)。
這種方式,也可以通過原型鏈實(shí)現(xiàn)繼承。由于低版本的瀏覽器是不支持Object.create的。所以這里簡(jiǎn)單介紹下兼容版本:
Object.create = function(prototype){ function F(){} F.prototype = prototype; return new F(); }原理是定義一個(gè)空的構(gòu)造函數(shù),然后修改其原型,使之成為一個(gè)跳板,可以將原型鏈傳遞到真正的prototype。
六、函數(shù)化繼承上述兩種實(shí)現(xiàn)方式,都存在一個(gè)問題:不存在私有屬性和私有方法。也就是說,存在被篡改的風(fēng)險(xiǎn)。
接下來就用函數(shù)化來化解這個(gè)問題。function book(spec, my){ var that = {}; // 私有變量 spec.name = spec.name || ""; // 書名 spec.page = spec.page || 0; // 頁(yè)數(shù) spec.classify = spec.classify || ""; // 類型 var getName = function(){ console.log(spec.name); }; var getPage = function(){ console.log(spec.page); }; var getClassify = function(){ console.log(spec.classify); }; that.getName = getName; that.getPage = getPage; that.getClassify = getClassify; return that; } function computer(spec, my){ spec = spec || {}; spec.classify = "computer"; var that = book(spec, my); var say = function(){ console.log("I"m "+ spec.name); }; that.say = say; return that; } var Ninja = computer({name: "JavaScript忍者秘籍", page: 350});函數(shù)化的優(yōu)勢(shì),就是可以更好地進(jìn)行封裝和信息隱藏。
也許有人疑惑為什么用以下這種方式聲明和暴露方法:var say = function(){ console.log("I"m "+ spec.name); }; that.say = say;其實(shí)是為了保護(hù)對(duì)象自身的完整性。即使that.say被外部篡改或破壞掉,function computer內(nèi)部的say方法仍然能夠正常工作。
另外,解釋下that、spec和my的作用:that是一個(gè)公開數(shù)據(jù)存儲(chǔ)容器,暴露出去的數(shù)據(jù)接口,都放到這個(gè)容器
spec是用來存儲(chǔ)創(chuàng)建新實(shí)例所需的信息,屬于實(shí)例之間共同編輯的數(shù)據(jù)
my是用來存儲(chǔ)父類、子類之間共享的私密數(shù)據(jù)容器,外部是訪問不到的。
七、ES6繼承最后,看下現(xiàn)代版ES6的類繼承。不禁感慨以前的刀耕火種,是多么折磨人
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/96422.html
摘要:格式子類名父類名好處提高了代碼的復(fù)用性提高了代碼的維護(hù)性通過少量的修改,滿足不斷變化的具體要求讓類與類產(chǎn)生了一個(gè)關(guān)系,是多態(tài)的前提要求有共同的屬性或操作有細(xì)微的差別繼承的弊端讓類的耦合性增強(qiáng)。 showImg(https://segmentfault.com/img/remote/1460000019321816?w=600&h=242); 第二階段 JAVA面向?qū)ο?第二章 繼承 其...
摘要:繼承簡(jiǎn)介在的中的面向?qū)ο缶幊蹋^承是給構(gòu)造函數(shù)之間建立關(guān)系非常重要的方式,根據(jù)原型鏈的特點(diǎn),其實(shí)繼承就是更改原本默認(rèn)的原型鏈,形成新的原型鏈的過程。 showImg(https://segmentfault.com/img/remote/1460000018998684); 閱讀原文 前言 JavaScript 原本不是純粹的 OOP 語(yǔ)言,因?yàn)樵?ES5 規(guī)范中沒有類的概念,在 ...
摘要:的繼承方式屬于原型式繼承,非常靈活。當(dāng)使用關(guān)鍵字執(zhí)行類的構(gòu)造函數(shù)時(shí),系統(tǒng)首先創(chuàng)建一個(gè)新對(duì)象,這個(gè)對(duì)象會(huì)繼承自構(gòu)造函數(shù)的原型對(duì)象新對(duì)象的原型就是構(gòu)造函數(shù)的屬性。也就是說,構(gòu)造函數(shù)用來對(duì)生成的新對(duì)象進(jìn)行一些處理,使這個(gè)新對(duì)象具有某些特定的屬性。 繼承這個(gè)東西在Javascript中尤其復(fù)雜,我掌握得也不好,找工作面試的時(shí)候在這個(gè)問題上栽過跟頭。Javascript的繼承方式屬于原型式繼承,...
摘要:繼承方式繼承方式限定了基類成員在派生類中的訪問權(quán)限,包括公有的私有的和受保護(hù)的。所以子類給父類引用賦值也是可以的,相當(dāng)于給子類對(duì)象中繼承的父類部分起了別名。如圖成員函數(shù)也是如此,當(dāng)子類與父類具有函數(shù)名相同的函數(shù)時(shí),還是符合就近原則。 ...
摘要:子類不是父類實(shí)例的問題是由類式繼承引起的。所以寄生式繼承和構(gòu)造函數(shù)繼承的組合又稱為一種新的繼承方式。但是這里的寄生式繼承處理的不是對(duì)象,而是類的原型??瓷先ヂ晕?fù)雜,還得好好研究。 寄生組合式繼承(終極繼承者) 前面學(xué)習(xí)了類式繼承和構(gòu)造函數(shù)繼承組合使用,也就是組合繼承,但是這種繼承方式有個(gè)問題,就是子類不是父類的實(shí)例,而子類的原型是父類的實(shí)例。子類不是父類實(shí)例的問題是由類式繼承引起的。...
閱讀 3863·2021-10-12 10:12
閱讀 1496·2021-10-11 10:58
閱讀 2329·2021-10-09 10:01
閱讀 2648·2021-09-24 09:48
閱讀 2733·2021-09-09 11:38
閱讀 3561·2019-08-30 15:44
閱讀 1770·2019-08-30 14:22
閱讀 546·2019-08-29 12:42