亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 開發 > JS > 正文

javascript面向對象三大特征之繼承實例詳解

2024-05-06 16:53:34
字體:
來源:轉載
供稿:網友

本文實例講述了javascript面向對象三大特征之繼承。分享給大家供大家參考,具體如下:

繼承

在JavaScript中的繼承的實質就是子代可以擁有父代公開的一些屬性和方法,在js編程時,我們一般將相同的屬性放到父類中,然后在子類定義自己獨特的屬性,這樣的好處是減少代碼重復。繼承是面向對象的基礎,是代碼重用的一種重要機制。

——此文整理自 《jQuery 開發從入門到精通》 ,這是本好書,講的很詳細,建議購買閱讀。

繼承的作用

實現繼承的主要作用是:

① 子類實例可以共享超類屬性和方法。
② 子類可以覆蓋和擴展超類屬性和方法。

繼承的分類

在JavaScript中是不支持類的概念,使用構造器機制來實現類的特性。
JavaScript中類的繼承不止一種,主要包括:類繼承(構造函數繼承),原型繼承,實例繼承,復制繼承,克隆繼承,混合繼承,多重繼承等。

類繼承

類繼承也叫構造函數繼承,其表現形式是在子類中執行父類的構造函數。實現本質:比如把一個構造函數A的方法賦值為另一個構造函數B,然后調用該方法,使構造函數A在構造函數B內部執行,這是構造函數B就擁有了構造函數A中定義的屬性和方法。這就是B類繼承A類。示例如下:

function A(x){  this.x = x;  this.say = function() {   console.log(this.x + ' say');  }}function B(x,y) {  this.m = A; // 把構造函數A作為一個普通函數引給臨時方法m()  this.m(x); // 把當前參數作為值傳給構造函數A,并且執行  delete this.m; // 清除臨時方法  this.y = y;  this.call = function(){   console.log(this.y);  }}// 測試類繼承var a = new A(1);var b = new B(2,3);a.say(); // 1 sayb.say(); // 2 sayb.call(); // 3

上面的實現方式很巧妙對吧,但是這種設計方式太隨意,缺乏嚴密性。嚴禁的設計模式應該考慮到各種可能存在的情況和類繼承關系中的互相耦合性。所以一般我們盡可能把子類自身的方法放在原型里去實現。下面這種創建方式會更好:

function A(x){ this.x = x; this.say = function() {  console.log(this.x + ' say'); }}function B(x,y){ this.y = y; A.call(this,x); // 在構造函數B內調用超類A,實現綁定,用call來實現借用}B.prototype = new A(); // 設置原型鏈,建立繼承關系B.prototype.constructor = B; // 恢復B的原型對象的構造函數為B,如果不操作就會指向AB.prototype.gety = function(){ // 給類B添加新的方法 return this.y;}// 測試 類繼承var a = new A('A');var b = new B('Bx','By');a.say(); // A sayb.say(); // Bx sayconsole.log(b.gety()); // Byconsole.log(B.prototype.__proto__ === A.prototype); // true;console.log(b.constructor === B); // true 這里也可以把B中的 B.prototype.constructor = B; 去除,結果為false

在js中實現類繼承,需要設置3點:

① 在子類構造函數結構體內,使用函數call()調用父類構造函數,把子類的參數傳遞給調用函數如上面的例子:A.call(this,x) 這樣子類可以繼承父類的所有屬性和方法。
② 在子類和父類之間建立原型鏈,如上例:B.prototype = new A() 為了實現類的繼承必須保證他們原型鏈上的上下級關系。即設置子類的prototype 屬性指向父類的一個實例即可。
③ 恢復子類原型對象的構造函數, 如上例:B.prototype.constructor = B

在類繼承中,call() 和 apply() 方法被頻繁使用,它們之間的功能和用法都是相同的,唯一區別就是第2個參數類型不同。

此處需要提一下,就是類的構造函數中的成員,一般稱之為本地成員,而類的原型成員就是類的原型中的成員,此處我們只考慮原型中的成員繼承。本地成員繼承可以用call 和 apply。下面我們來看下類繼承的原型成員的繼承封裝函數:

在函數體內,首先定義一個空函數F(),用來實現功能中轉,把它的原型指向父類的原型,把空函數的實例傳遞給子類的原型,這樣就避免了直接實例化父類引發的內存問題,因為實際開發中,父類可能很大,實例化后,會占用很大一部分內存。

// 定義一個繼承函數function extend(Sub,Sup){ // 有兩個入口參數,Sub是子類,Sup是父類 var F = function(){}; // 建立一個臨時的構造函數 F.prototype = Sup.prototype; // 把臨時構造函數的原型指向父類的原型 Sub.prototype = new F(); // 實例化臨時類,此處相當于把子類的原型指向父類的實例 Sub.prototype.constructor = Sub; // 恢復子類的構造函數 Sub.sup = Sup.prototype; // 在子類中定義一個本地屬性存儲超類原型,可避免子類和超類耦合 if(Sup.prototype.constructor === Object.prototype.constructor) { // 檢測超類構造器是否為Object構造器  Sup.prototype.constructor = Sup; }}// 下面定義兩個類用來測試上面的繼承函數function A(x,y) { this.x = x; this.y = y;}A.prototype.add = function() { return (this.x-0) + (this.y-0); // 此處-0 的目的是確保字符串類型可轉成數值型}A.prototype.minus = function() { return this.x - this.y;}function B(x,y) { A.apply(this,[x,y]);}// 開始實現類繼承中的原型成員繼承extend(B,A);// 為了不與A類中的代碼耦合可以單獨為B定義一個同名的addB.prototype.add = function() { return B.sup.add.call(this); // 避免代碼耦合}// 測試繼承var b = new B(1,2);console.log(b.minus()); // -1console.log(b.add()); // 3

原型繼承

原型繼承是js中最通用的繼承方式,不用實例化對象,通過直接定義對象,并被其他對象引用,這樣形成的一種繼承關系,其中引用對象被稱為原型對象。

function A(){ this.color = 'red';}function B(){}function C(){}B.prototype = new A();C.prototype = new B();// 測試原型繼承var c = new C();console.log(c.color); // red

原型繼承顯得很簡單,不需要每次構造都調用父類的構造函數,也不需要通過復制屬性的方式就能快速實現繼承。但它也存在一些缺點:

① 每個類型只有一個原型,所以不支持多重繼承
② 不能很好的支持多參數或動態參數的父類,顯得不夠靈活。
③ 占用內存多,每次繼承都需要實例化一個父類,這樣會存在內存占用過多的問題。

實例繼承

實例化類可創建新的實例對象,這個實例對象將繼承類的所有特征。

function Arr() { var a = new Array(); return a;}var arr = new Arr();arr[0] = 1;arr[1] = 2;console.log(arr); // [1,2]console.log(Array.isArray(arr)); // trueconsole.log(arr instanceof Array); // trueconsole.log(arr instanceof Arr); // false

通過構造函數中完成對類的實例化操作,然后返回實例對象,這就是實例繼承的由來。實例繼承可實現對所有對象的繼承,包括自定義類,核心對象和DOM對象。但是也有一些缺點

① 實例繼承無法傳遞動態參數,它是封閉在函數體內試下你,不能通過call和apply來實現動態傳參。
② 實例繼承只返回一個對象,不支持多重繼承
③ 實例繼承對象它仍然保持與原對象的實例關系,無法實現繼承對象是封裝類的實例。如:console.log(arr instanceof Arr); // false

復制繼承

復制繼承就是利用for in 遍歷對象成員,逐一復制給另一個對象。通過這種方式來實現繼承。

function A(){ this.color = 'red';}A.prototype.say = function() { console.log(this.color);}var a = new A();var b = {};// 開始拷貝for(var item in a) { b[item] = a[item];}// 開始測試console.log(b.color); // redb.say(); // red.

我們把它封裝一下:

Function.prototype.extend = function(obj){ for(item in obj){  this.constructor.prototype[item] = obj[item]; }}function A(){ this.color = 'green';}A.prototype.say = function(){ console.log(this.color);}// 測試var b = function(){};b.extend(new A());b.say(); // green

復制繼承實際上是通過反射機制復制類對象中的可枚舉屬性和方法來模擬繼承。這種可以實現多繼承。但也有缺點:

① 由于是反射機制,不能繼承非枚舉類型的屬性和方法。對于系統核心對象的只讀方法和屬性也無法繼承。
② 執行效率差,這樣的結構越龐大,低效就越明顯。
③ 如果當前類型包含同名成員,這些成員會被父類的動態復制給覆蓋。
④ 多重繼承中,復制繼承不能清晰描述父類和子類的相關性。
⑤ 在實例化后才能遍歷成員,不夠靈活,也不支持動態參數
⑥ 復制繼承僅僅是簡單的引用賦值,如果父類成員包含引用類型,那么也會帶來很多副作用,如不安全,容易遭受污染等。

克隆繼承

通過對象克隆方式繼承,可以避免賦值對象成員帶來的低效。
為Function對象擴展一個clone方法。該方法可把參數對象賦值給一個空的構造函數的原型對象,然后返回實例化后的對象,這樣該對象就擁有構造哈數包含的所有成員了。

Function.prototype.clone = function(obj){ function Temp(){}; Temp.prototype = obj; return new Temp();}function A(){ this.color = 'purple';}var o = Function.clone(new A());console.log(o.color); // purple

混合繼承

混合繼承是把多種繼承方式一起使用,發揮各個優勢,來實現各種復雜的應用。最常見的就是把類繼承和原型繼承一起使用。

function A(x,y){ this.x = x; this.y = y;}A.prototype.add = function(){ return (this.x-0) + (this.y-0);}function B(x,y){ A.call(this,x,y);}B.prototype = new A();// 測試var b = new B(2,1);console.log(b.x); // 2console.log(b.add()); // 3

多重繼承

繼承一般包括單向繼承和多向繼承,單向繼承模式較為簡單,每個子類有且僅有一個超類,多重繼承是一個比較復雜的繼承模式。一個子類可擁有多個超類。JavaScript原型繼承不支持多重繼承,但可通過混合模式來實現多重繼承。下面讓類C來繼承類A和類B:

function A(x){ this.x = x;}A.prototype.hi = function(){ console.log('hi');}function B(y){ this.y = y;}B.prototype.hello = function(){ console.log('hello');}// 給Function增加extend方法Function.prototype.extend = function(obj) { for(var item in obj) {  this.constructor.prototype[item] = obj[item]; }}// 在類C內部實現繼承function C(x,y){ A.call(this,x); B.call(this,y);};C.extend(new A(1));C.extend(new B(2));// 通過復制繼承后,C變成了一個對象,不再是構造函數了,可以直接調用C.hi(); // hiC.hello(); // helloconsole.log(C.x); // 1console.log(C.y); // 2

一個類繼承另一個類會導致他們之間產生耦合,在js中提供多種途徑來避免耦合的發生如 摻元類

摻元類是一種比較特殊的類,一般不會被實例化或者調用,定義摻元類的目的只是向其他類提供通用的方法。

// 定義一個摻元類function F(x,y){ this.x = x; this.y = y;}F.prototype = { getx:function(){  return this.x; }, gety:function(){  return this.y; }}// 原型拷貝函數function extend(Sub,Sup){ // Sub 子類 , Sup 摻元類 for(var item in Sup.prototype){  if(!Sub.prototype[item]){ // 如果子類沒有存在同名成員   Sub.prototype[item] = Sup.prototype[item]; // 那么復制摻元類成員到子類原型對象中  } }}// 定義兩個子類 A,Bfunction A(x,y){ F.call(this,x,y);}function B(x,y){ F.call(this,x,y);}// 調用extend函數實現原型屬性,方法的拷貝extend(A,F);extend(B,F);console.log(A.prototype);// 測試繼承結果var a = new A(2,3);console.log(a.x); // 2console.log(a.getx()); // 2console.log(a.gety()); // 3var b = new B(1,2);console.log(b.x); // 1console.log(b.getx()); // 1console.log(b.gety()); // 2

通過此種方式把多個子類合并到一個子類中,就實現了多重繼承。

希望本文所述對大家JavaScript程序設計有所幫助。


注:相關教程知識閱讀請移步到JavaScript/Ajax教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
欧美性xxxx在线播放| 日韩视频永久免费观看| 国产精品精品国产| 国产精品香蕉国产| 国产成人综合亚洲| 97在线精品国自产拍中文| 国产精品18久久久久久首页狼| 操91在线视频| 久久久久久国产精品三级玉女聊斋| 美日韩精品免费视频| 日韩国产高清视频在线| 亚洲男人天天操| 欧美中文字幕在线观看| 国产亚洲美女久久| 色一情一乱一区二区| 国产精品久久久av| 俺去了亚洲欧美日韩| 成人黄色大片在线免费观看| 九九精品在线播放| 久久91亚洲精品中文字幕奶水| 国产日韩欧美另类| 久久亚洲精品网站| 欧美精品一本久久男人的天堂| 久久精品视频99| 亚洲毛茸茸少妇高潮呻吟| 成人黄色激情网| 久久天天躁夜夜躁狠狠躁2022| 日韩av在线精品| 在线精品高清中文字幕| 午夜精品久久久久久久男人的天堂| 欧美性猛xxx| 66m—66摸成人免费视频| 欧美—级高清免费播放| 疯狂做受xxxx欧美肥白少妇| 色中色综合影院手机版在线观看| 久久久久久久久国产精品| 在线中文字幕日韩| 久久精品精品电影网| 国产精品va在线播放| 欧美日韩国产精品一区二区不卡中文| 欧美孕妇毛茸茸xxxx| 色综合久久中文字幕综合网小说| 国产精品香蕉在线观看| 成人免费视频在线观看超级碰| 国产一区二区三区18| 欧美一二三视频| 久久久999成人| 久久99精品久久久久久噜噜| 91免费综合在线| 国产成人精品在线视频| 成人免费自拍视频| 国产成人午夜视频网址| 97视频在线观看播放| 久久精品国产亚洲| 亚洲毛片在线观看.| 国产美女主播一区| 亚洲欧美国产一区二区三区| 国产精品久久久久久亚洲影视| 国产精品旅馆在线| 91精品视频播放| 欧美一级淫片丝袜脚交| 国产精品亚洲第一区| 国产精品极品美女在线观看免费| 欧美国产欧美亚洲国产日韩mv天天看完整| 欧美午夜视频在线观看| 亲爱的老师9免费观看全集电视剧| 成人国内精品久久久久一区| 国产精品高潮呻吟久久av无限| 欧美在线视频观看| 亚洲欧洲在线观看| 亚洲综合大片69999| 日韩在线观看免费高清| 日韩欧美第一页| 国产男人精品视频| 91九色视频在线| 一区二区亚洲欧洲国产日韩| 亚洲第一区第一页| 欧美日韩色婷婷| 日韩一区二区av| 亚洲午夜激情免费视频| 日本成人免费在线| 国产精品aaaa| 不卡av电影在线观看| 一区二区三区无码高清视频| 中文字幕日韩欧美在线视频| 国产精品视频精品| 久久久久久综合网天天| 久久久久久久影视| 日韩小视频在线| 96sao精品视频在线观看| 狠狠干狠狠久久| 91av在线播放| 午夜精品一区二区三区视频免费看| 国产成人精品一区| 国产精品吹潮在线观看| 欧美乱妇高清无乱码| 欧美成人黑人xx视频免费观看| 亚洲精品日产aⅴ| 欧美国产在线电影| 欧美激情在线有限公司| 亚洲精品网站在线播放gif| 亚洲精品电影在线| 亚洲第一中文字幕| 精品香蕉一区二区三区| 久久偷看各类女兵18女厕嘘嘘| 欧美精品videofree1080p| 好吊成人免视频| 亚洲黄色片网站| 国产精品偷伦视频免费观看国产| 日本一区二三区好的精华液| 国产福利精品在线| 久久久电影免费观看完整版| 国产精品久久久久999| 日本精品视频在线观看| 亚洲专区中文字幕| 九九视频这里只有精品| 成人深夜直播免费观看| 久久精品成人一区二区三区| 国产一区二区三区视频免费| 亚洲激情成人网| 最近更新的2019中文字幕| 欧美国产日韩中文字幕在线| 日韩av免费在线播放| 精品人伦一区二区三区蜜桃免费| 欧美诱惑福利视频| 深夜福利日韩在线看| 国产精品免费在线免费| 欧美亚洲另类制服自拍| 永久免费精品影视网站| 欧美一性一乱一交一视频| 热久久免费视频精品| 国产精品久久久久久久美男| 亚洲欧美日韩一区在线| 久操成人在线视频| 亚洲欧美制服中文字幕| 国产视频精品自拍| 亚洲淫片在线视频| 欧美成人一区在线| 91香蕉嫩草影院入口| 日本三级韩国三级久久| 国产一区二区激情| 欧美剧在线观看| 亚洲va男人天堂| 国产精品自拍偷拍视频| 欧洲美女免费图片一区| 91探花福利精品国产自产在线| 国产福利成人在线| 国产成人精品一区二区在线| 91亚洲精品一区二区| 91在线免费看网站| 91高清在线免费观看| 亚洲国产日韩一区| 欧美高清videos高潮hd| 色综合久久中文字幕综合网小说| 亚洲成色777777在线观看影院| 国产亚洲欧美日韩一区二区| 欧美噜噜久久久xxx| 国产日韩在线看| 51久久精品夜色国产麻豆| 国产成人精品视频| 97人洗澡人人免费公开视频碰碰碰| 久久不射热爱视频精品| 最近2019中文字幕第三页视频| 日本中文字幕不卡免费|