JavaScript:基於原型鏈的繼承

来源:http://www.cnblogs.com/xiaoxiaoyihan/archive/2016/06/22/5607404.html
-Advertisement-
Play Games

原型鏈的基本思想是: 利用原型讓一個引用類型繼承另一個引用類型的屬性和方法 。 構造函數、原型和實例的關係 :每個構造函數都有一個原型對象,原型對象都包含一個指向構造函數的指針,而實例都包含一個指向原型對象的內部指針。 如果讓原型對象等於另一個對象的實例,這樣原型對象將包含一個指向另一個原型的指針, ...


原型鏈的基本思想是:利用原型讓一個引用類型繼承另一個引用類型的屬性和方法

構造函數、原型和實例的關係:每個構造函數都有一個原型對象,原型對象都包含一個指向構造函數的指針,而實例都包含一個指向原型對象的內部指針。

如果讓原型對象等於另一個對象的實例,這樣原型對象將包含一個指向另一個原型的指針,相應地,另一個原型中也包含著一個指向另一個構造函數的指針。

實現原型鏈的基本模式:

function SuperType() {
    this.property = true;
}
SuperType.prototype.getSuperValue = function () {
    return this.property;
};

function SubType() {
    this.subproperty = false;
}

// 繼承SuperType
SubType.prototype = new SuperType();
SubType.prototype.getSubValue = function () {
    return this.subproperty;
};

var instance = new SubType();
alert(instance.getSuperValue());    // true

SubType繼承了SuperType,繼承是通過創建SuperType的實例,並將該實例賦給SubType.prototype實現的。實現的本質是重寫原型對象,換成一個新類型的實例。這樣,原來存在於SuperType的實例中的屬性和方法,也存在與SubType.prototype中了。然後給SubType.prototype添加一個方法,這樣就繼承了SuperType的屬性和方法的基礎上又添加了一個方法。

上例中的實例關係表示如下:

上面沒有使用SubType預設提供的原型,而是給它換了一個新原型;這個新原型就是SuperType的實例。新原型內部還有一個執行SuperType的原型的指針。結果變成了instance指向SubType的原型,SubType的原型又指向SuperType的原型。getValue()方法仍然還在SuperType.prototype中,但prototype則位於SubType.prototype中。這是因為property是一個實例屬性,而getSuperValue()則是一個原型方法。既然SubType.prototype現在是SuperType的實例,那麼property自然位於該實例中。

註意:instance.constructor現在指向的是SuperType,因為SubType的原型指向了另一個對象——SuperType的原型,這個原型對象的constructor屬性指向的是SuperType。

當以讀取模式訪問一個屬性時,首先會在實例中搜索該屬性。如果沒有找到該屬性。則會繼續搜索實例的原型。通過原型鏈實現繼承的情況下,搜索過程就得以沿著原型鏈繼續向上。

預設的原型

所有引用類型都預設繼承了Object,而這個繼承也是通過原型鏈實現的。所有函數的預設原型都是Object的實例。因此預設原型都會包含一個內部指針,指向Object.prototype。這就是為什麼自定義類型都會繼承toString()、valueOf()等方法的原因。

完整的原型鏈:

在上面的繼承體系中,SubType繼承了SuperType,SuperType繼承了Object。當調用了instance.toString()時,實際調用的是保存在Object.prototype中的那個方法。

確定實例和原型的關係

可以通過兩種方式來確定原型和實例之間的關係:

使用instanceof操作符

alert(instance instanceof  Object);
alert(instance instanceof  SuperType);
alert(instance instanceof  SubType);

由於原型鏈的關係,上面全部返回true。

使用isPrototypeOf()方法

alert(Object.prototype.isPrototypeOf(instance));
alert(SuperType.prototype.isPrototypeOf(instance));
alert(SubType.prototype.isPrototypeOf(instance));

謹慎定義方法

給原型添加方法的代碼一定要放在替換原型的語句之後。

function SuperType() {
    this.property = true;
}

SuperType.prototype.getSuperValue = function () {
    return this.property;
};

function SubType() {
    this.subproperty = false;
}
SuperType.prototype = new SuperType();

// 添加方法
SubType.prototype.getSubValue = function () {
    return this.subproperty;
};

// 覆蓋超類中的方法
SubType.prototype.getSuperValue = function () {
    return false;
};

var instance = new SubType();
alert(instance.getSuperValue());    // false

上面的例子必須註意的是,在用SuperType的實例替換原型之後,再定義那兩個方法。

另外,在通過原型鏈實現繼承時,不能使用該對象字面量創建原型方法。因為這樣做會重寫原型鏈:

function SuperType() {
    this.property = true;
}

SuperType.prototype.getSuperValue = function () {
    return this.property;
};

function SubType() {
    this.subproperty = false;
}

// 繼承SuperType
SubType.prototype = new SuperType();

// 使用字面量添加新方法,導致上一行代碼無效
SubType.prototype = {
    getSubValue :function() {
        return this.subproperty;
    },

    someOtherMethod: function () {
        return false;
    }
};

var instance = new SubType();
alert(instance.getSuperValue());    // error

上例將SuperType的實例賦值給原型,緊接著又將原型替換成一個對象字面量而導致的問題。現在的原型包含一個Object的實例,而非SuperType的實例,SubType和SuperType之間已經沒有關係了。

原型鏈的問題

前面已經介紹過,包含引用類型值得原型屬性會被所有實例共用;而這也正是為什麼要在構造函數中,而不是在原型對象中定義屬性的原因。

function SuperType() {
    this.colors = ["red", "blue", "green"];
}
function SubType() {
    
}

SubType.prototype = new SuperType();

var instance1 = new SubType();
instance1.colors.push("black");
alert(instance1.colors);        // "red", "blue", "green", "black"

var instance2 = new SubType();
alert(instance2.colors);        // "red", "blue", "green", "black"

在上面的例子中,SuperType構造函數中定義了一個colors屬性,該屬性包含一個數組,SuperType的每個實例都會有各自包含自己數組的colors屬性。當SubType通過原型鏈繼承了SuperType之後,SubType.prototype就變成了SuperType的一個實例,所以它也擁有了一個它自己的colors屬性。但是,SubType的所有實例都會共用這一個colors屬性。

另一問題是,沒有辦法在不影響所有對象實例的情況下,給超類的構造函數傳遞參數。


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

-Advertisement-
Play Games
更多相關文章
  • 0-判斷變數、參數是否初始化 if(x){} //變數被初始化了或者變數不為空或者變數不為零 1-聲明函數不需要聲明返回值、參數類型,句尾甚至都不需要';' function sum(i1,i2){return i1+i2} 2-直接聲明匿名函數立即使用 var f=function(i1,i2){ ...
  • Adobe Dreamweaver雖然非常好用,但它並不是唯一一個能夠設計、開發、發佈精彩網站的Web開發集成環境。我們的開源世界里有很多非常棒的可以完全替代Dreamweaver的各種功能的優秀Web開發工具,更重要的,是免費的。如果你正在尋找Dreamweaver的替代品,下麵這8款軟體你應該優 ...
  • 常用的非同步方式有三種:回調函數、事件監聽以及發佈訂閱,當非同步多且依賴關係很嚴重時,常用的這三種非同步方式不是很完美,ES6中Promise的出現完美地解決了這一弊端,成為非同步調用最佳的方式。該隨筆分為5部分:1、常用三種非同步方式介紹;2、Promise概述;3、Promise的使用;4、模擬Promi... ...
  • 根據選擇器、DOM元素或 jQuery 對象來檢測匹配元素集合,如果其中至少有一個元素符合這個給定的表達式就返回true。 如果沒有元素符合,或者表達式無效,都返回'false'。 '''註意:'''在jQuery 1.3中才對所有表達式提供了支持。在先前版本中,如果提供了複雜的表達式,比如層級選擇 ...
  • 作者:vousiu 出處:http://www.cnblogs.com/vousiu 本實例參考自Mike Cantelon等人的《Node.js in Action》一書。 本實例要實現如下一個聊天App。左上的“Winter”為顯示的房間的名字。中間為聊天消息,斜體字為系統消息,非斜體為聊天內容 ...
  • jquery.each 方法 方法一 ...
  • 又到了畢業季,很多小伙伴們都到了找工作的時候了,好多小伙伴問我有前端的面試題麽?答:沒有。 呃呃… … 小伙伴本寶寶真的沒有騙你們,我從畢業到現在一直在一家公司沒有換過,所以手裡壓根沒有面試題。我們公司招聘也壓根不需要什麼面試題。因為那些都是可以百度的哈哈。 但是大部分公司還是有面試題的,所以征求大 ...
  • Ext JS 6 如何從資料庫動態抓取JS腳本內容來動態創建Web窗體... ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...