JS: 原型與原型鏈

来源:https://www.cnblogs.com/guolao/archive/2019/02/28/10450288.html
-Advertisement-
Play Games

原型與原型鏈 javascript 創建對象 類與構造函數是大多數編程語言所擁有的,而借鑒了 C 與 JAVA 的 javascript 也是有類和構造函數的,不過 javascript 的實現不太一樣。 上面的例子中, 就是構造函數, 就是它的實例,但是它對共用性不太好,所以有了原型模式。 原型模 ...


原型與原型鏈

javascript 創建對象


類與構造函數是大多數編程語言所擁有的,而借鑒了 C 與 JAVA 的 javascript 也是有類和構造函數的,不過 javascript 的實現不太一樣。

// before ES6
// 構造函數模式
function Person(name){
  this.name = name;
    this.sayName = function() {
      console.log(this.name);
    }
}

var p = new Person();
console.log(p instanceof Person); // true

上面的例子中,Person就是構造函數,p就是它的實例,但是它對共用性不太好,所以有了原型模式。

// 原型模式
function Person(){}
Person.prototype.name = 'kobe';
Person.prototype.sayName = function() {
  console.log(this.name);
}

var p1 = new Person();
var p2 = new Person();

p1.sayName(); // kobe
p2.sayName(); // kobe

原型模式創建的實例都可以共用Person.prototype的屬性和方法,而prototype是 javascript 實現類的一個關鍵所在。

prototype


在 javascript 中,每個函數都有一個prototype屬性,這個屬性指向函數的原型對象,上面的例子,可以用下圖解釋,圖中用Person.prototype表示 Person 的原型對象。

prototype

constructor


Person 是構造函數,有prototype指針指向原型對象,而Person.prototype也有一個constructor屬性指向構造函數。

constructor

簡單來說,就是 javascript 會在函數創建的時候為函數添加一個prototype屬性,這個屬性是指向函數的原型對象的指針,而原型對象也會獲得一個constructor屬性,這個屬性是一個指向函數本身的指針,即指向構造函數。

function Person(){}
Person.prototype.name = 'kobe';
Person.prototype.sayName = function() {
  console.log(this.name);
}

Person.prototype.constructor == Person; // true

__proto__


函數有prototype,那對象呢?其實對象內部也有一個[[prototype]]指針,這個指針指向創建實例對象的構造函數的原型對象。

在 ES5 之前的語言標準里,是不允許訪問這個屬性的,但瀏覽器都實現了一個__proto__[[prototype]]進行訪問操作,所以 ES5 增加了一個Object.getPrototypeOf()方法來訪問[[prototype]]

Object.getPrototypeOf(object)方法返回指定對象的原型(內部[[Prototype]]屬性的值)。

在 ES5 中,如果參數不是一個對象類型,將拋出一個 TypeError 異常。在 ES6 中,參數會被強制轉換為一個 Object。

建議在代碼中使用Object.getPrototypeOf()來訪問內部[[Prototype]]屬性,不建議使用非標準的__proto__,為了方便區別,文中使用__proto__來表示[[prototype]]

回到上面的例子,當調用 Person 來創建實例的時候,該實例會獲得一個__proto__指針指向構造函數的原型對象。

proto

正是因為創建的 p1、p2 實例都擁有__proto__指向構造函數(Person)的原型對象(Person.prototype),它們才能共用Person.prototype的屬性和方法。

function Person(){}
Person.prototype.name = 'kobe';
Person.prototype.sayName = function() {
  console.log(this.name);
}

let p1 = new Person();
let p2 = new Person();

Object.getPrototypeOf(p1) == Object.getPrototypeOf(p2); // true

簡單來說,就是在 javascript 中,每一個對象(除null)在創建的時候都會將其與另一個對象進行關聯,而關聯的這個對象就是所謂的原型。

使用isPrototypeOf()方法就能確定這種關聯:

Person.prototype.isPrototypeOf(p1); // true
Person.prototype.isPrototypeOf(p2); // true

屏蔽性


還是這個例子:

function Person(){}
Person.prototype.name = 'kobe';
Person.prototype.sayName = function() {
  console.log(this.name);
}

let p1 = new Person();
// 訪問 p1 的 name
p1.name; // kobe

當我們通過實例 p1 訪問name屬性的時候,javascript 引擎會先在實例 p1 中查找name,當發現 p1 沒有這個屬性,就會通過__proto__向它指向的原型對象進行查找,找到就返回這個屬性的值,也就是說訪問name執行了兩次查找。

如果 p1 自己添加了name屬性,就會在第一次查找時返回值:

// 在 p1 中添加 name
p1.name = 'jordan';

// 只會執行一次查詢
p1.name; // jordan

// 原型中的值並未改變
Object.getPrototypeOf(p1).name; // kobe

也就是說,在實例上添加name屬性後,該屬性就會屏蔽原型中的那個屬性,但並不會改變原型中的該屬性的值。

原型鏈


既然在 javascript 中,所有對象(除null)都有__proto__,而實例 p1 指向Person.prototype,那Person.prototype對象的__proto__又指向哪裡呢?

Object.getPrototypeOf(Person.prototype) == Object.prototype; // true

答案是Object.prototype,因為原型對象是通過構造函數 Object 來創建的,所以它指向Object.prototype

Object.prototype

那 Object.prototype 的__proto__又指向哪裡呢?它指向這條鏈的終點:null,代表無。

Object.getPrototypeOf(Object.prototype); // null

null

回到上面所說的查找name屬性,如果在第二次都沒有查找到name屬性,就會沿著這條鏈繼續向上查找,直到終點都沒有找到,就會返回 undefined。

function Person(){}

let p1 = new Person();
p1.name; // undefined

上圖中虛線部分由原型相互關聯組成的鏈狀結構就是所謂的原型鏈。

備註


不得不說,《javascript高級程式設計》這本書把原型講得很透徹,今天再看一遍依然感覺通透。


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

-Advertisement-
Play Games
更多相關文章
  • 基本思路 紅色:為可見區域 黑色方框:元素,不可見。 通過絕對定位方式,把黑色方框,移動到紅色可見區別,來實現圖片切換。 實例 創建幻燈實例對象 源碼:https://pan.baidu.com/s/1-A0GkZ2hOpuVJ5dg1y6mnQ 樣本:http://js.zhuamimi.cn/% ...
  • http-equiv l 設定頁面使用的字元集 l IE8瀏覽器去模擬特定版本的IE瀏覽器的渲染方式,以此來解決部分相容問題。 l 自動刷新並指向新頁面 l 如果網頁過期,那麼自動刪除本地cookie l 強制頁面在當前視窗中以獨立頁面顯示,可以防止自己的網頁被別人當作一個frame頁調用 l 緩存 ...
  • 現在構建任何類型的軟體項目最流行的方法這是使用類。在這篇文章中,探討用 JavaScript 實現類的不同方法,以及如何構建類的結構。首先從深入研究原型工作原理,並分析在流行庫中模擬基於類的繼承的方法。 接下來是講如何將新的語法轉製為瀏覽器識別的語法,以及在 Babel 和 TypeScript 中 ...
  • 使用CSS3實現動畫勾選 相信大家在項目中會經常遇到這種需求:勾選框。現在用CSS3來實現一個動畫勾選,只需要一個標簽即可完成: 這次需要用到CSS中偽類 after,這個小技巧也是很容易忘記的,所以決定記錄起來~ 首先給標簽加寬高加背景色: 接下來利用偽類給標簽添加元素,同時水平垂直居中: 變成這 ...
  • 1、首先要安裝nodejs和npm。 下載nodejs安裝,下載地址:https://nodejs.org/en/ 安裝很簡單一路next即可。 安裝完成後可以在cmd視窗輸入node -v 和 npm -v 查看是否安裝成功 2、vue-cli腳手架安裝 CMD命令行輸入:npm install ...
  • sudo -s npm install -g yarn react-native-cli ...
  • 今天碰到的一個比較煩人的問題是,在body上添加事件處理函數,發現在iphone上怎麼也沒辦法觸發事件,找了半天,發現iPhone處理冒泡事件的規則: 1.點擊某個元素; 2.如果這個元素上沒有處理該事件,則繼續向上冒泡,直到body下的子節點為止。如果此時還是沒有元素處理這個事件,則丟棄該事件,不 ...
  • 如果你是一個人在自學前端開發,或者是對前端開發有比較濃厚的興趣正想踏入前端領域,只要你在前端自學路上遇到了自己無法解決的技術難題,那麼儘管將你的疑惑交給我的小伙伴兒們吧,我們都是一群在前端自學路上摸爬滾打的有志青年,希望你可以來和我們共同交流。同時也希望你能獻出自己的一份力,幫助我的小伙伴兒們解決他 ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...