詳解JavaScript對象繼承方式

来源:https://www.cnblogs.com/jofun/archive/2018/04/06/8727814.html
-Advertisement-
Play Games

一、對象冒充 其原理如下:構造函數使用 this 關鍵字給所有屬性和方法賦值(即採用類聲明的構造函數方式)。因為構造函數只是一個函數,所以可使 Parent 構造函數 成為 Children 的方法,然後調用它。Children 就會收到 Parent 的構造函數中定義的屬性和方法。原理:就是把 ... ...


一、對象冒充

其原理如下:構造函數使用 this 關鍵字給所有屬性和方法賦值(即採用類聲明的構造函數方式)。因為構造函數只是一個函數,所以可使 Parent 構造函數
成為 Children 的方法,然後調用它。Children 就會收到 Parent 的構造函數中定義的屬性和方法。例如,用下麵的方式定義 Parent 和 Children:

]// 父類構造函數
var Parent = function(name){
    this.name = name;

    this.sayHi = function(){
        console.log("Hi! " + this.name + ".");
    }
};

// 子類構造函數
var Children = function(name){
    this.method = Parent;
    this.method(name); // 實現繼承的關鍵
    delete this.method;

    this.getName = function(){
        console.log(this.name);
    }
};

var p = new Parent("john");
var c = new Children("joe");

p.sayHi(); // 輸出: Hi! john.
c.sayHi(); // 輸出: Hi! joe.
c.getName(); // 輸出: jo

 

原理:就是把 Parent 構造函數放到 Children 構造函數裡面執行一次。那為什麼不直接執行,非要轉個彎把 Parent 賦值給 Children 的 method 屬性再執行呢?
這跟 this 的指向有關,在函數內 this 是指向 window 的。當將 Parent 賦值給 Children 的 method 時, this 就指向了 Children 類的實例。

 

二、原型鏈繼承

眾所周知,JavaScript 是一門基於原型的語言,在 JavaScript 中 prototype 對象的任何屬性和方法都被傳遞給那個類的所有實例。原型鏈利用這種功能來實現繼承機制:

// 父類構造函數
var Parent = function(){
    this.name = "john";

    this.sayHi = function(){
        console.log("Hi! " + this.name + ".");
    }
};

// 子類構造函數
var Children = function(){};

Children.prototype = new Parent(); // 實現繼承的關鍵

var p = new Parent();
var c = new Children();

p.sayHi(); // 輸出: Hi! john.
c.sayHi(); // 輸出: Hi! john.

 

註意:調用 Parent 的構造函數,沒有給它傳遞參數。這在原型鏈中是標準做法。要確保構造函數沒有任何參數。

 

三、使用 call 或 applay 方法

這個方法是與對象冒充方法最相似的方法,因為它也是通過改變了 this 的指向而實現繼承:

// 父類構造函數
var Parent = function(name){
    this.name = name;

    this.sayHi = function(){
        console.log("Hi! " + this.name + ".");
    }
};

// 子類構造函數
var Children = function(name){
    Parent.call(this, name); // 實現繼承的關鍵

    this.getName = function(){
        console.log(this.name);
    }
};

var p = new Parent("john");
var c = new Children("joe");

p.sayHi(); // 輸出: Hi! john.
c.sayHi(); // 輸出: Hi! john.
c.getName(); // 輸出: joe

 

apply 方法本人就不舉列了,它和 call 方法的區別在於它的第二個參數必須是數組。

 

四、混合方式

對象冒充的主要問題是必須使用構造函數方式,這不是最好的選擇。不過如果使用原型鏈,就無法使用帶參數的構造函數了。如何選擇呢?答案很簡單,兩者都用。
在 JavaScript 中創建類的最好方式是用構造函數定義屬性,用原型定義方法。這種方式同樣適用於繼承機制:

// 父類構造函數
var Parent = function(name){
    this.name = name;
};

Parent.prototype.sayHi = function(){
    console.log("Hi! " + this.name + ".");
};

// 子類構造函數
var Children = function(name, age){
    Parent.call(this, name); // 實現繼承的關鍵
    this.age = age;
};

Children.prototype = new Parent(); // 實現繼承的關鍵

Children.prototype.getAge = function(){
    console.log(this.age);
};

var p = new Parent("john");
var c = new Children("joe",30);

p.sayHi(); // 輸出: Hi! john.
c.sayHi(); // 輸出: Hi! joe.
c.getAge(); // 輸出: 30

 

五、使用Object.create 方法

Object.create 方法會使用指定的原型對象及其屬性去創建一個新的對象:

// 父類構造函數
var Parent = function(name){
    this.name = name;
};

Parent.prototype.sayHi = function(){
    console.log("Hi! " + this.name + ".");
};

// 子類構造函數
var Children = function(name, age){
    Parent.call(this, name); // 實現繼承的關鍵
    this.age = age;
};

Children.prototype = Object.create(Parent.prototype); // 實現繼承的關鍵
Children.prototype.constructor = children; // @

Children.prototype.getAge = function(){
    console.log(this.age);
};

var p = new Parent("john");
var c = new Children("joe",30);

p.sayHi(); // 輸出: Hi! john.
c.sayHi(); // 輸出: Hi! joe.
c.getAge(); // 輸出: 30

 

@ 當執行 Children.prototype = Object.create(Parent.prototype) 這個語句後,Children 的 constructor 就被改變為 Parent ,因此需要將 Children.prototype.constructor 重
新指定為 Children 自身。

 

六、extends 關鍵字實現繼承

這個是 ES6 的語法糖,下麵看下es6實現繼承的方法:

class Parent {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }
}

class Children extends Parent {
  constructor(name, age, job) {
    this.job = job; // 這裡會報錯
    super(name, age);
    this.job = job; // 正確
  }
}

 

上面代碼中,子類的constructor方法沒有調用super之前,就使用this關鍵字,結果報錯,而放在super方法之後就是正確的。子類Children的構造函數之中的super(),代表調用父類Parent的構造函數。這是必須的,否則 JavaScript 引擎會報錯。

 

註意,super雖然代表了父類Parent的構造函數,但是返回的是子類Children的實例,即super內部的this指的是Children,因此super()在這裡相當於Parent.prototype.constructor.call(this)

 


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

-Advertisement-
Play Games
更多相關文章
  • 背景 項目 :移動端H5電商項目 痛點 :慢!!! 初始方案 :最基本的圖片懶載入,靜態資源放到cdn,predns等等已經都做了。但是還是慢,慢在哪? 顯而易見的原因 :由於前後端分離,所有的數據都由介面下發,之後根據模板渲染頁面。也就是說,我們需要先載入js,等到js載入完畢之後,請求介面,介面 ...
  • 只要調用函數進行執行,都必須加括弧。 函數是一個對象,函數名是指向這個對象的指針。 函數名後面加上括弧就表示立即調用執行這個函數裡面的代碼。 使用不帶圓括弧的函數是訪問函數的指針,而非調用函數。 函數名後面加括弧,就直接執行函數返回值。 函數名後面不加括弧,表示函數名賦值給click等的事件,觸發c ...
  • 最近做小程式開發,出於練手,也是工作需要,就做了個微信小程式的類似於酒店預訂的日曆插件。先上圖; 這個插件分為上下兩部分,上邊是tab欄,會根據當前的日期自動定位到當前,並展示以後7天的日期,下邊為內容展示,隨tab欄變化而變化。思路:首先用`new Data()`時間對象初始化時間,獲取當前的日期 ...
  • 原文地址: "A cartoon guide to Flux by Lin Clark" Flux在目前web開發中最受歡迎也較不被人理解,本文會以簡單易懂的方式解釋它。 出現問題 首先,我要聲明Flux所解決的基本問題。Flux是一種幫助你處理數據的模式。Flux和React都由Facebook開 ...
  • webpack優化方案 1. 優化開發體驗 1-1. 加快構建速度 ① 縮小文件搜索範圍 由於 Loader 對文件的轉換操作很耗時,需要讓儘可能少的文件被 Loader 處理,用include和exclude去縮小; resolve.modules用於配置 Webpack 去哪些目錄下尋找第三方模 ...
  • "— Java攻城獅學習路線 —" 一. JavaScript基礎 輸出 使用 window.alert() 彈出警告框。 使用 document.write() 方法將內容寫到 HTML 文檔中。 使用 innerHTML 寫入到 HTML 元素。 使用 console.log() 寫入到瀏覽器的 ...
  • 常用的一些快捷鍵: Windows + e 我的電腦Ctrl + Tab 網頁間不同頁面切換F2 重命名Ctrl+Shift+S 另存為 前端的一些常識:前端意義:將效果圖生成網頁網頁組成:文字、圖片、輸入框、視頻、音頻、超鏈接Web標準:Html 結構標準;Css 表現標準;Js 行為標準 瀏覽器 ...
  • 最近想用LayaBox做個小游戲,然而Laya本身不自帶構建工具。然後覺得寫模塊化的東西還是用webpack好使,用es6的語法也比較清晰。 於是就裝了webpack,只用babel-loader來編譯用es6寫的代碼。配置文件如下: 一開始我沒有設定mode,雖然我在babelrc裡面寫了comp ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...