關於原型鏈,原來這麼簡單?—————終結__proto__和prototype的那些事

来源:https://www.cnblogs.com/kbaoq/archive/2019/08/14/11354549.html
-Advertisement-
Play Games

今天,一個技術群里小朋友提出一個問題: 我默念心中的萬能公式,答案一下就出來了: a; 報錯(f.b is not a function); a; b; 這下子出題人產生了疑惑,你是控制台敲出來的吧! 但其實,原型鏈真的很簡單。話不多說,開始表演! 首先,我們簡單介紹一下,實例化一個對象(new)到 ...


今天,一個技術群里小朋友提出一個問題:

Object.prototype.a = function () {
    console.log('a')
}

Function.prototype.b = function () {
    console.log('b')
}

function F(){}
var f = new F();

f.a();
f.b();
F.a();
F.b();

我默念心中的萬能公式,答案一下就出來了:

a;

報錯(f.b is not a function);

a;

b;

這下子出題人產生了疑惑,你是控制台敲出來的吧!

但其實,原型鏈真的很簡單。話不多說,開始表演!

首先,我們簡單介紹一下,實例化一個對象(new)到底做了什麼?

function Base() {
    this.a = function () {
        console.log('我是Base中的a')
    }
}

Base.prototype.b = function () {
    console.log('我是Base prototype上的b')
}

var obj = new Base();
// 實際上做了以下幾件事
// var obj = {};
// obj.__proto__ = Base.prototype;
// Base.call(obj);
// 第一行,我們創建了一個空對象obj
// 第二行,我們將這個空對象的__proto__成員指向了Base函數對象prototype成員對象
// 第三行,我們將Base函數中this上的成員賦值給obj

這就去控制台檢驗一下:

好,可以開始解題,回顧一下小朋友提出的問題:

Object.prototype.a = function () { console.log('a') }
Function.prototype.b = function () { console.log('b') }
function F(){}
var f = new F();
f.a();f.b();F.a();F.b();

我們展開f的原型鏈:

f.__proto__ === F.prototype;

// 因為prototype本質也是對象,繼承自Object,所以F.prototype.__proto__ === Object.prototype
f.__proto__.__proto__ === Object.prototype;

// 按上一條,會得出Object.prototype.__proto__ = Object.prototype,那樣會永無止境,因此js中把Object.prototype.__proto_直接賦值成null
f.__proto__.__proto__.__proto__ === null;

我們會發現,f的原型鏈中,根本沒有Function.prototype什麼事,所以答案出來了,f.a()輸出a,f.b會報錯;

我們再展開F的原型鏈:

F.__proto__ === Function.prototype;

// 因為prototype本質也是對象,繼承自Object,所以Function.prototype.__proto__ === Object.prototype
F.__proto__.__proto__ === Object.prototype;

f.__proto__.__proto__.__proto__ === null;

OK,Function.prototype和Object.prototype都在原型鏈上,都會有輸出,答案揭曉,F.a()輸出a,F.b()輸出b;

前文我提到了萬能公式,吃瓜群眾表示,難道公式就是這個?當然不是,請聽我細細道來;

剛纔的故事還沒結束,我心血來潮回問了小朋友一個問題,就剛纔你的條件Object.a();Object.b();Function.a();Function.b();會輸出什麼?

小朋友答曰:a; b; a; b;

不錯不錯,但他接了一句(他的1和4其實答錯了,後續會告訴原因):

1. Object.a();  直接prototype取值;

2. Object是Function.prototype的實例,可以繼承b;

3. Function.__proto__ === Function.prototype;

4. Function.b();直接prototype取值;

 

???Object.a第一步就直接到Object.prototype上找?這可能也是大家弄不清原型鏈的一大問題,話不多說,請攤開Object的原型鏈:

// Object是函數,繼承自Function
Object.__proto__ === Function.prototype;

Object.__proto__.__proto__ === Object.prototype;

Object.__proto__.__proto__.__proto__ === null;

因此,細心的朋友已經發現他的錯誤了,Object.a其實是訪問到Object.__proto__.__proto__時才從Object.prototype上找到相應的a();

同樣展開Function的原型鏈,就不再贅述了:

// Function自身也是個函數,因此繼承自己
Function.__proto__ === Function.prototype;

Function.__proto__.__proto__ === Object.prototype;

Function.__proto__.__proto__.__proto__ === null;

為了引導出萬能公式,我再次發出了靈魂拷問:

// 在剛纔的前提下
var c = 1;
console.a();// a
console.b();// console.b is not a function
c.a();// a
c.b();// c.b is not a function
console.log.a();// a
console.log.b();// b

這時,學會展開原型鏈的同學已經明白答案了,我就直接說出我的萬能公式:

在js中,萬物皆對象,只要在Object.prototype上寫的方法,萬物都能訪問到;而Function.prototype上的方法,只有能通過()方式調用的函數,才能訪問到;

因此我只需要查看這個對象可不可以通過函數()的形式調用,就能確定他是否能訪問Function.prototype。再次回顧出題人的問題,f僅僅是個對象,f()是會報not is a function錯誤的,而F()是可以調用的函數,一下子得出 a 報錯 a b的答案,學到了是不是感覺自己也棒棒噠~~~

最終Cober老師還是給出了自己的殺手鐧面試題,畢竟原型鏈還有另一層面試方法:

Object.prototype.a = function () {
    console.log('我是Object中的a')
}
Object.prototype.b = function(){
    console.log('我是Object中的b')
}
Function.prototype.a = function () {
    console.log('我是Function中的a')
}
Function.prototype.b = function () {
    console.log('我是Function中的b')
}
function F(){
    this.a = function () {
        console.log('我是F中的a')
    }
}
F.prototype.a = function () {
    console.log('我是F的prototype中的a')
}
var f = new F();
f.a();f.b();F.a();F.b();Object.a();Object.b();Function.a();Function.b();

(提示:原型鏈調用順序是f.a -> f.__proto__.a -> f.__proto__.__proto__.a,直到訪問到null)


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

-Advertisement-
Play Games
更多相關文章
  • 首先mysql官網下載yum源https://dev.mysql.com/downloads/repo/yum/然後將下載好的rpm文件安裝並校驗[root@elegant-snap-3 /stage]$ rpm -ivh mysql80-community-release-el7-2.noarch... ...
  • 本視頻為 Google Flutter 團隊的軟體工程師 Xiao Yu 在 2018 谷歌開發者大會做的演講,演講題目是《Flutter 的性能測試和理論》。 這個視頻里將會通過近半個小時的視頻和演示帶大家瞭解 Flutter 應用渲染時的時間消耗,瞭解這些之後會更好的幫助開發者們發現應用的性能問 ...
  • 前兩天在論壇上看到一個問題,大意是怎麼在UBUNTU下使用NDK r20編譯FFmpeg。我第一反應是不該用r20,因為我在很早前用過沒有gcc版本的NDK,發現有很多問題不能編譯,就立馬回覆了個使用r12b來編譯。回到家我細想了一下,如果我就是想要用r20的NDK編譯最新的FFmpeg呢?不如我們 ...
  • 文章轉載自:http://www.pythonheidong.com/blog/article/3310/ 註:本文來自“安卓公車” Android面試題 1. 下列哪些語句關於記憶體回收的說明是正確的? (b ) A、 程式員必須創建一個線程來釋放記憶體 B、 記憶體回收程式負責釋放無用記憶體 C、 記憶體 ...
  • 文章轉載自:http://www.pythonheidong.com/blog/article/3307/ 上一篇文章列出了共32道IOS面試題: http://www.cnblogs.com/fkdd/archive/2012/03/13/2394724.html 下麵從第一題開始解答: 題目:1 ...
  • Javascript 有一個 main thread 主線程和 call-stack 調用棧(執行棧),所有的任務都會被放到調用棧等待主線程執行。 JS調用棧採用的是後進先出的規則,當函數執行的時候,會被添加到棧的頂部,當執行棧執行完成後,就會從棧頂移出,直到棧內被清空。 Javascript單線程 ...
  • 一、CSS顯示模式​ 1.在HTML中HTML將所有的標簽分為兩類,分別是容器類和文本級。在CSS中CSS也將所有的標簽分為兩類,分別是塊級元素和行內元素 2.什麼是塊級元素呢?什麼是行內元素​? (1)塊級元素會獨占一行 (2)行內元素不會獨占一行 3.塊級元素 p div h ul ol dl ...
  • 作為一個致力於前端開發的人員,能夠熟練掌握javascript的原理和機制是每個小白的必經之路,這也是最痛苦的。有人說前端功力好不好最主要的就是看對js的掌握能力,有人說十年也啃不完一門javascript。而我們能夠知道的是:javascript是每個前端學習的核心技能(想想之後的node.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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...