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