Javascript中的prototype與繼承

来源:http://www.cnblogs.com/niuboren/archive/2017/02/06/6369043.html
-Advertisement-
Play Games

通常來說,javascript中的對象就是一個指向prototype的指針和一個自身的屬性列表。javascript創建對象時採用了寫時複製的理念。 只有構造器才具有prototype屬性,原型鏈繼承就是創建一個新的指針,指向構造器的prototype屬性。 prototype屬性之所以特別,是因為 ...


通常來說,javascript中的對象就是一個指向prototype的指針和一個自身的屬性列表javascript創建對象時採用了寫時複製的理念。 只有構造器才具有prototype屬性,原型鏈繼承就是創建一個新的指針,指向構造器的prototype屬性。 prototype屬性之所以特別,是因為javascript時讀取屬性時的遍歷機制決定的。本質上它就是一個普通的指針。   構造器包括:
1.Object 2.Function 3.Array 4.Date 5.String
下麵我們來舉一些例子吧  

 

  1. //每個function都有一個預設的屬性prototype,而這個prototype的constructor預設指向這個函數
  2. //註意Person.constructor 不等於 Person.prototype.constructor. Function實例自帶constructor屬性
  3. functionPerson(name){
  4. this.name = name;
  5. };
  6. Person.prototype.getName =function(){
  7. returnthis.name;
  8. };
  9. var p =newPerson("ZhangSan");
  10. console.log(Person.prototype.constructor===Person);// true
  11. console.log(p.constructor===Person);// true ,這是因為p本身不包含constructor屬性,所以這裡其實調用的是Person.prototype.constructor

 

 

運行一下 »

我們的目的是要表示
1.表明Person繼承自Animal 2. 表明p2是Person的實例 
我們修改一下prototype屬性的指向,讓Person能獲取Animal中的prototype屬性中的方法。也就是Person繼承自Animal(人是野獸) 
 

 

  1. functionPerson(name){
  2. this.name = name;
  3. };
  4. Person.prototype.getName =function(){
  5. returnthis.name;
  6. };
  7. var p1 =newPerson("ZhangSan");
  8. console.log(p.constructor===Person);// true
  9. console.log(Person.prototype.constructor===Person);// true
  10.  
  11. functionAnimal(){}
  12. Person.prototype =newAnimal();//之所以不採用Person.prototype = Animal.prototype,是因為new 還有其他功能,最後總結。
  13. var p2 =newPerson("ZhangSan");
  14. //(p2 -> Person.prototype -> Animal.prototype, 所以p2.constructor其實就是Animal.prototype.constructor)
  15. console.log(p2.constructor===Person);// 輸出為false ,但我們的本意是要這裡為true的,表明p2是Person的實例。此時目的1達到了,目的2沒達到。

運行一下 »

但如果我們這麼修正

 

Person.prototype = new Animal(); Person.prototype.constructor = Person; 
這時p2.consturctor是對了,指向的是Person,表示p2是Person類的實例,但是新問題出現了。此時目的2達到了,目的1沒達到。 目的1和目的2此時互相矛盾,是因為此時prototype表達了矛盾的兩個意思,
1表示父類是誰 2作為自己實例的原型來複制 
因此我們不能直接使用prototype屬性來表示父類是誰,而是用getPrototypeOf()方法來知道父類是誰。   

 

  1. Person.prototype =newAnimal();
  2. Person.prototype.constructor=Person
  3. var p2 =newPerson("ZhangSan");
  4. p2.constructor//顯示 function Person() {}
  5. Object.getPrototypeOf(Person.prototype).constructor//顯示 function Animal() {}

 

  就把這兩個概念給分開了 ,其實通過使用 hasOwnProperty()方法,什麼時候訪問的是實例屬性,什麼時候訪問的是原型屬性就一清二楚了

new做了哪些事情?

當代碼var p = new Person()執行時,new 做瞭如下幾件事情:

創建一個空白對象

創建一個指向Person.prototype的指針

將這個對象通過this關鍵字傳遞到構造函數中並執行構造函數。

具體點來說,在下麵這段代碼中,

 

  1. Person.prototype.getName =function(){}
如果我們通過

 

 

 

  1. var person =newPerson();
  2.  
  3. 其實類似於
  4.  
  5. var person =newObject();
  6.  
  7. person.getName =Person.prototype.getName;

 

 

因此通過person.getName()調用方法時,this指向的是這個新創建的對象,而不是prototype對象。

 這其實在給現有函數加上新功能的情況下會用到,我們可以這麼擴展現有的方法:

 

 

  1. //function myFunc 的寫法基本上等於 var myFunc = new Function();
  2.  
  3. function myFunc (){
  4. }
  5.  
  6. myFunc =function(func){
  7.   //可以在這裡做點其他事情
  8. returnfunction(){
  9.      //可以在這裡做點其他事情
  10. return func.apply(this,arguments);
  11. }
  12. }(myFunc)

 

 

 也可以在Function.prototype方法里直接通過this來訪問上面代碼的myFunc所指向的對象

 

 

  1. function myFunc (){
  2. }
  3.  
  4. if(!Function.prototype.extend){
  5. Function.prototype.extend =function(){
  6. var func =this;
  7.  
  8. returnfunction(){
  9. func.apply(this,arguments);
  10. }
  11. }
  12. };
  13.  
  14. var myFunc = myFunc.extend();

 

 

總結一下

如果採用Person.prototype  = Animal.prototype來表示Person繼承自Animal, instanceof方法也同樣會顯示p也是Animal的實例,返回為true.

之所以不採用此方法,是因為下麵兩個原因:

1.new 創建了一個新對象,這樣就避免了設置Person.prototype.constructor = Person 的時候也會導致Animal.prototype.constructor的值變為Person,而是動態給這個新創建的對象一個constructor實例屬性。這樣實例上的屬性constructor就覆蓋了Animal.prototype.constructor,這樣Person.prototype.constructor和Animal.prototype.contructor就分開了。

2.Animal自身的this對象的屬性沒辦法傳遞給Person

但是像下麵這樣直接調用構造函數又可能失敗,或者產生其他影響。

 

  1. Person.prototype =newAnimal();

 

 為了避免這種情況,所以我們引入了一個中間函數。所以正確的做法應該是

 

 

  1. Person.prototype =(funtion(){
  2.  
  3.   function F(){};
  4.  
  5.   F.prototype =Animal.prototype
  6.  
  7.   returnnew F();
  8.  
  9. })()

 

 
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 百萬行代碼架構遷移——有感 背景 身處互聯網暫不知名公司,16年6月份接受公司項目,主要職責是線上項目問題維護、項目開發SE工作附帶項目組事務管理,目前領隊十來人。由於項目整體研發已有4年,中間團隊人員換了幾波,技術總監和項目架構核心設計人員先後離職,項目前景不容樂觀。 舊項目結構描述 java系項 ...
  • 一、概述 代理模式為另一個對象提供一個替身或占位符以控制對這個對象的訪問。其實就是代理就是做到類似轉發的功能,針對不同代理,轉發的具體實現不同。 二、解決問題 從原理知道他就是控制客戶對一個對象的訪問,它跟現實中的中介代理類似,只是作為代表做一些受理工作,真正執行的並不是它自己。比如買火車票,外面有 ...
  • 1、建造者模式UML 圖1. 建造者模式UML 2、C++實現 C++實現類視圖: 圖2. 建造者模式C++實現的類視圖 其中,Product的實現代碼是(ProductA和ProductB的代碼不再列出): Builder實現代碼是: ConcreteBuilderA的實現代碼是: Concret ...
  • 定義:策略模式定義了演算法族,分別封裝起來,讓他們之間可以相互替換,此模式讓演算法的變化獨立於使用演算法的客戶。 一個使用了策略模式案例的UML類圖:(https://github.com/sunhuace/GOF-23.git) 個人見解:策略模式通過封裝演算法族,使用多態的方式持有FlyBehavevi ...
  • 1、抽象工廠模式UML 圖1. 抽象工廠模式的UML 2、C++實現 C++實現類圖為: 圖2. 抽象工廠模式的C++實現類圖 其中,AbstractFactory的實現代碼為: ConcreteFactoryA的實現代碼為: 其中,ConcreteFactory2的代碼與ConcreteFacto ...
  • 最近研究下java語言,根據一般使用的情況,寫了個連接通訊服務的框架; 框架結構 C-Manager-S; 把所有通訊內容抽取成三個方法介面:GetData,SetData,帶返還的Get; 所有數據都處理為byte[];客戶端與服務端和管理器以及服務端有多重處理模式 管理信息: 1.不需要中心管理 ...
  • A 調用攝像頭拍照,自定義裁剪編輯頭像 【新錄針對本系統的視頻教程,手把手教開發一個模塊,快速掌握本系統】B 集成代碼生成器 [正反雙向](單表、主表、明細表、樹形表,開發利器)+快速構建表單; 技術:313596790 freemaker模版技術 ,0個代碼不用寫,生成完整的一個模塊,帶頁面、建表 ...
  • 無阻塞載入 把js放在head里,瀏覽器是怎麼去執行它的呢,是按順序載入還是並行載入呢?在舊的瀏覽器下,都是按照先後順序來載入的,這就保證了載入的js依賴不會發生問題。但是少部分新的瀏覽器已經開始允許並行載入js了,也就是說可以同時下載js文件,但是還是按先後順序執行文件的。 下載是非同步的沒問題,但 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...