Javascript構造函數的繼承

僅供學習參考,原文鏈接:http://www.ruanyifeng.com/blog/2010/05/object-oriented_javascript_inheritance.html

今天要介紹的是,對象之間的"繼承"的五種方法。

比如,現在有一個"動物"對象的構造函數。


  function Animal(){

    this.species = "動物";

  }

還有一個"貓"對象的構造函數。


  function Cat(name,color){

    this.name = name;

    this.color = color;

  }

怎樣才能使"貓"繼承"動物"呢?

一、 構造函數綁定

第一種方法也是最簡單的方法,使用call或apply方法,將父對象的構造函數綁定在子對象上,即在子對象構造函數中加一行:

  function Cat(name,color){

    Animal.apply(this, arguments);

    this.name = name;

    this.color = color;

  }

  var cat1 = new Cat("大毛","黃色");

  alert(cat1.species); // 動物

二、 prototype模式

第二種方法更常見,使用prototype屬性。

如果"貓"的prototype對象,指向一個Animal的實例,那么所有"貓"的實例,就能繼承Animal了。

  Cat.prototype = new Animal();

  Cat.prototype.constructor = Cat;

  var cat1 = new Cat("大毛","黃色");

  alert(cat1.species); // 動物

代碼的第一行,我們將Cat的prototype對象指向一個Animal的實例。

  Cat.prototype = new Animal();

它相當于完全刪除了prototype 對象原先的值,然后賦予一個新值。但是,第二行又是什么意思呢?

  Cat.prototype.constructor = Cat;

原來,任何一個prototype對象都有一個constructor屬性,指向它的構造函數。如果沒有"Cat.prototype = new Animal();"這一行,Cat.prototype.constructor是指向Cat的;加了這一行以后,Cat.prototype.constructor指向Animal。

  alert(Cat.prototype.constructor == Animal); //true

更重要的是,每一個實例也有一個constructor屬性,默認調用prototype對象的constructor屬性。

  alert(cat1.constructor == Cat.prototype.constructor); // true

因此,在運行"Cat.prototype = new Animal();"這一行之后,cat1.constructor也指向Animal!

  alert(cat1.constructor == Animal); // true

這顯然會導致繼承鏈的紊亂(cat1明明是用構造函數Cat生成的),因此我們必須手動糾正,將Cat.prototype對象的constructor值改為Cat。這就是第二行的意思。

這是很重要的一點,編程時務必要遵守。下文都遵循這一點,即如果替換了prototype對象,

  o.prototype = {};

那么,下一步必然是為新的prototype對象加上constructor屬性,并將這個屬性指回原來的構造函數。

  o.prototype.constructor = o;

三、 直接繼承prototype

第三種方法是對第二種方法的改進。由于Animal對象中,不變的屬性都可以直接寫入Animal.prototype。所以,我們也可以讓Cat()跳過 Animal(),直接繼承Animal.prototype。

現在,我們先將Animal對象改寫:

  function Animal(){ }

  Animal.prototype.species = "動物";

然后,將Cat的prototype對象,然后指向Animal的prototype對象,這樣就完成了繼承。

  Cat.prototype = Animal.prototype;

  Cat.prototype.constructor = Cat;

  var cat1 = new Cat("大毛","黃色");

  alert(cat1.species); // 動物

與前一種方法相比,這樣做的優點是效率比較高(不用執行和建立Animal的實例了),比較省內存。缺點是 Cat.prototype和Animal.prototype現在指向了同一個對象,那么任何對Cat.prototype的修改,都會反映到Animal.prototype。

所以,上面這一段代碼其實是有問題的。請看第二行

  Cat.prototype.constructor = Cat;

這一句實際上把Animal.prototype對象的constructor屬性也改掉了!

  alert(Animal.prototype.constructor); // Cat

四、 利用空對象作為中介

由于"直接繼承prototype"存在上述的缺點,所以就有第四種方法,利用一個空對象作為中介。

  var F = function(){};

  F.prototype = Animal.prototype;

  Cat.prototype = new F();

  Cat.prototype.constructor = Cat;

F是空對象,所以幾乎不占內存。這時,修改Cat的prototype對象,就不會影響到Animal的prototype對象。

  alert(Animal.prototype.constructor); // Animal

我們將上面的方法,封裝成一個函數,便于使用。

  function extend(Child, Parent) {

    var F = function(){};

    F.prototype = Parent.prototype;

    Child.prototype = new F();

    Child.prototype.constructor = Child;

    Child.uber = Parent.prototype;

  }

使用的時候,方法如下

  extend(Cat,Animal);

  var cat1 = new Cat("大毛","黃色");

  alert(cat1.species); // 動物

這個extend函數,就是YUI庫如何實現繼承的方法。

另外,說明一點,函數體最后一行

  Child.uber = Parent.prototype;

意思是為子對象設一個uber屬性,這個屬性直接指向父對象的prototype屬性。(uber是一個德語詞,意思是"向上"、"上一層"。)這等于在子對象上打開一條通道,可以直接調用父對象的方法。這一行放在這里,只是為了實現繼承的完備性,純屬備用性質。

五、 拷貝繼承

上面是采用prototype對象,實現繼承。我們也可以換一種思路,純粹采用"拷貝"方法實現繼承。簡單說,如果把父對象的所有屬性和方法,拷貝進子對象,不也能夠實現繼承嗎?這樣我們就有了第五種方法。

首先,還是把Animal的所有不變屬性,都放到它的prototype對象上。

  function Animal(){}

  Animal.prototype.species = "動物";

然后,再寫一個函數,實現屬性拷貝的目的。

  function extend2(Child, Parent) {

    var p = Parent.prototype;

    var c = Child.prototype;

    for (var i in p) {

      c[i] = p[i];

      }

    c.uber = p;

  }

這個函數的作用,就是將父對象的prototype對象中的屬性,一一拷貝給Child對象的prototype對象。

使用的時候,這樣寫:

  extend2(Cat, Animal);

  var cat1 = new Cat("大毛","黃色");

  alert(cat1.species); // 動物

轉載于:https://www.cnblogs.com/zhangym118/p/6419277.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/396712.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/396712.shtml
英文地址,請注明出處:http://en.pswp.cn/news/396712.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

python輸入字符串str_python字符串(str)

#value "raitOrEi"#v value.capitalize()#首字母大寫#print(v)#v1 v.casefold()#全部變小寫,不只是英文的,其他語言特殊的大小寫也變換#print(v1)#v2 v.lower()#只是英文變小寫#print(v2)#設置寬度,并將內容居中#20 代指總長度…

html5 audio api 錄音,如何使用HTML5 Web Audio API錄制我的聲音

在webkit瀏覽器上,您可以將get user media api與webkitGetUserMedia一起使用 – 如html5rocks所示.如果你想用你的聲音來創建javascript事件(例如控制屏幕上的對象)你必須分析傳入的聲音(例如事件1的高頻率 – 事件2的低頻率,語音分析要復雜得多,見下文)另外,還有chrome的’x-w…

修改密碼

在updateservlet.java中寫了方法&#xff0c;修改用戶密碼&#xff0c;代碼不成功求大神指教&#xff0c;代碼如下&#xff1a; updateadminpw.jsp <% page contentType"text/html;charsetgb2312" pageEncoding"gb2312" %><% taglib uri"ht…

MlLib--邏輯回歸筆記

批量梯度下降的邏輯回歸可以參考這篇文章&#xff1a;http://blog.csdn.net/pakko/article/details/37878837 看了一些Scala語法后&#xff0c;打算看看MlLib的機器學習算法的并行化&#xff0c;那就是邏輯回歸&#xff0c;找到package org.apache.spark.mllib.classification下…

mysql相關命令操作

2019獨角獸企業重金招聘Python工程師標準>>> 遠程連接容器中的mysql&#xff1a;mysql -h 192.168.5.116 -P 3306 -u root -p123456 啟動mysql容器&#xff1a; $ sudo docker pull mysql:5.6.35 $ sudo docker run --name mysql -p 12345:3306 -e MYSQL_ROOT_PASSW…

html實體注冊商標,html 注冊商標,html 注冊商標代碼

html中注冊的頁面用什么標簽寫好對于html中的注冊頁面&#xff0c;策朋專業辦理商標注冊、專利申請、版權登記保護&#xff0c;需要一個表格。使用標簽&#xff0c;輸入和按鈕標簽來組合成就。使用html作為注冊頁面。實際上&#xff0c;只要您能達到期望的效果&#xff0c;它的…

java已知一個二叉樹_#二叉樹復習#

#二叉樹復習#目錄滿二叉樹完全二叉樹平衡二叉樹二叉樹的主要性質--二叉樹的度--二叉樹的深度計算二叉樹的遍歷其他符號變量結點總數深度度為0的結點數/葉子結點數度為1的結點數度為2的結點數什么是滿二叉樹&#xff1f;二叉樹每層的結點數為。滿二叉樹總結點數&#xff1a;。圖…

hashtable - hashmap

http://www.importnew.com/24822.html轉載于:https://www.cnblogs.com/qinqiu/p/9711147.html

java 反射機制_基礎篇:深入解析JAVA反射機制

反射的概念java 的放射機制&#xff1a;在程序運行時&#xff0c;程序有能力獲取一個類的所有方法和屬性&#xff1b;并且對于任意一個對象&#xff0c;可以調用它的任意方法或者獲取其屬性通俗解析&#xff1a;java 文件需要編譯成. class 文件才能被 jvm 加載使用, 對象的. c…

構建之法閱讀筆記01

本學期閱讀計劃有兩個&#xff0c;一個是《構建之法》&#xff0c;另一個是《大道至簡》。 在快速閱讀構建之法后&#xff0c;我想提一下幾個問題&#xff1a; 1、軟件程序軟件工程&#xff0c;那么只會軟件工程是怎樣具體詳細的將程序變成合格的軟件的&#xff1f; 2、效能分析…

html div float center,跨瀏覽器實現float:center

跨瀏覽器實現float:center互聯網 發布時間&#xff1a;2008-10-17 19:26:11 作者&#xff1a;佚名 我要評論原文&#xff1a;http://www.macji.com/blog/article/to-achieve-cross-browser-css-float-center/to-achieve-cross-browser-css-float-center/我們都知道float…

博弈論中:納什均衡、純策略納什均衡、混合策略納什均衡、占優策略

納什均衡 納什均衡是由約翰福布斯納什&#xff08;John Forbes Nash&#xff09;在20世紀50年代提出的博弈論概念&#xff0c;用于描述博弈中的一種穩定狀態。在納什均衡狀態下&#xff0c;每個參與者都假定其他參與者的策略是已知的&#xff0c;他們選擇的策略是最優的&#…

工具_HBuilder使用快捷方式

HBuilder常用快捷鍵大概共9類&#xff08;【4 13 3】文件、編輯、插入&#xff1b;【4 9 8】選擇、跳轉、查找&#xff1b;【1 1 6】運行、工具、視圖&#xff09; 1.文件(4) 新建 Ctrl N 關閉 Ctrl F4 全部關閉 Ctrl Shift F4 屬性 Alt Enter 2.編輯(13) 激活代碼助…

oracle左連接沒用_一周零基礎學完Oracle數據庫第三天02

四、 多表查詢1 什么是多表查詢多表查詢&#xff1a;當查詢的數據并不是來源一個表時&#xff0c;需要使用多表鏈接操作完成查詢。根據 不同表中的數據之間的關系查詢相關聯的數據。多表鏈接方式&#xff1a; 內連接&#xff1a;連接兩個表&#xff0c;通過相等或不等判斷鏈接列…

weblogic啟動項目報錯找不到類_啟動類報錯是經常出現的事但是單一的從一個地方找原因會越找越錯...

Error starting ApplicationContext. To display the conditions report rerun your application with debug enabled.當我們看到這個報錯的時候有的說是jar包重復&#xff0c;有的說是Controller包和Application包處于平行位置&#xff0c;還有的覺得是RequestMapping的valu…

fis

fis3實時刷新 npm install -g fis3 進入相關目錄 發布&#xff1a; fis3 release 啟動&#xff1a; fis3 server start // 服務啟動后&#xff0c;會一直存在&#xff0c;重啟或者fis3 server stop 才會關閉服務 自動刷新 fis3 release -wL關閉服務 fis3 server stop …

深入理解javascript原型和閉包(7)——原型的靈活性

在Java和C#中&#xff0c;你可以簡單的理解class是一個模子&#xff0c;對象就是被這個模子壓出來的一批一批月餅&#xff08;中秋節剛過完&#xff09;。壓個啥樣&#xff0c;就得是個啥樣&#xff0c;不能隨便動&#xff0c;動一動就壞了。 而在javascript中&#xff0c;就沒…

微型計算機一般不采用的控制方式,微型計算機控制作業.doc

作業一PID控制器引言在實際的過程控制與運動控制系統中&#xff0c;PID家族占據有相當的地位&#xff0c;據統計&#xff0c;工業控制的控制器中PID類控制占有90%以上。PID控制器是最早出現的控制器類型&#xff0c;因為其結構簡單&#xff0c;各個控制器參數有著明顯的物理意義…

js根據毫米/厘米算像素px

<html><meta http-equiv"content-type" content"text/html;charsetutf-8"><body> 紙張寬度(毫米mm)&#xff1a;<input type"text" id"width" value"10"> <span id"width_px"><…

c語言為什么有這么多的編程環境?_為什么98%的程序員學編程都會從C語言開始?...

在互聯網蓬勃發展的時代&#xff0c;有一類人做出了巨大的貢獻&#xff0c;這一群人被大家稱之為程序員&#xff0c;怎樣才能成為一名優秀的程序員呢&#xff0c;為什么每一個程序員都需要學習C語言呢&#xff1f;就讓我來跟大家分享分享&#xff1a;壹第一&#xff1a;相比較其…