自己動手用原生實現 bind/call/apply

来源:https://www.cnblogs.com/LHLVS/archive/2019/03/25/10595784.html
-Advertisement-
Play Games

大家好!!!註冊一年多的第一篇博客。 自我介紹: 本人非電腦專業出身,轉行進入前端半年時間,寫的東西可能觀賞性不強,一起進步吧道友們。。。 接下來的一段時間, 我都會不定期整理自己理解的js知識點, 歡迎各路道友吐槽。 進入正題...... (針對新手,老司機不要嘲笑我) 首先, bind/cal ...


大家好!!!註冊一年多的第一篇博客。

自我介紹: 本人非電腦專業出身,轉行進入前端半年時間,寫的東西可能觀賞性不強,一起進步吧道友們。。。

接下來的一段時間, 我都會不定期整理自己理解的js知識點, 歡迎各路道友吐槽。

 

進入正題......  (針對新手,老司機不要嘲笑我)

 

首先, bind/call/apply 這改變this指向的三兄弟我們都很熟悉了, 還有其他改變this指向的方法這裡就不多說了哈,要不就跑題了。。。。

你需要知道的前提 : 這三貨都是函數原型(Function.prototype)上的方法, 所以只有函數可以調用。

              小白 : “原型是啥?”   每一個構造函數(其實就是普通函數,函數名首字母大寫而已)都有一個prototype原型對象,當你引用某個實例對象上的屬性時, 會先查找該對象本身有沒有該屬性,有就用,沒有就會去構造這個實例的構造函數的原型上去找,還沒有的話就會沿著構造函數的原型對象的__proto__屬性往上找......haha, 好像又跑題了, 關於原型鏈和繼承可以自行百度

 

真的進入正題。。。。。。

 

它們不是函數上的方法嗎, 我們先定義個函數, 後面來改變這個函數的this指向

function out(age, sex, type) {
    console.log(age, sex, this.age, this.sex, type);
}

分別輸出傳入的參數age, sex, type  和   this 上的age , sex, 

然後定義個對象, 後面讓this指向該對象,  沒錯,此對象描述的就是我

let  my = {
    age : 16,
    sex : 'handsome man'
};

先試試bind, 先會用然後再來實現, 由於bind可以傳兩次參數,你可以這樣傳

const bindFunction = out.bind(my,50); //this 指向my 不會直接執行 返回一個明確this指向的函數
bindFunction('women','bind'); // 傳參執行 

還可以這樣傳,想怎麼傳就怎麼傳,只要確保.bind後的第一個參數是你要改變this指向的對象, (如果什麼都不傳,this指向window)

const bindFunction = out.bind(my); //this 指向my 不會直接執行 返回一個明確this指向的函數
bindFunction('50','women','bind'); // 傳參執行 

執行後輸出 :

50 "women" 16 "handsome man" "bind"

總結一下我們要模擬的bind

1.  函數A調用bind返回一個可執行的函數B, 調用bind時可傳參 可不穿參, 不穿參時this指向window

2.  調用B可繼續傳參, 兩次傳參合並

3.   new B() 的構造函數依然是A, 而不是B,並且因為new操作符改變this指向的優先順序最高,所以如果使用了new操作符,this指向不應該變,就是該是啥是啥(劃重點)

上代碼 :

 

Function.prototype.myBind = function (target) { // bind 是 function 上的 方法  this 指向 target
    if (typeof  this !== 'function') {
        throw new TypeError('not a function')
    };
    const _this = this, // 保存一下this
        args = Array.prototype.slice.call(arguments, 1),// arguments是類數組,沒有 slice 方法 保存第一次傳入的參數
        temp = function () {}; // 定義一個中間函數
    const f = function () {
        return _this.apply(this instanceof  temp ? this : (target || window), args.concat([].slice.call(arguments))); // 合併兩次傳的參數
    };
    temp.prototype = _this.prototype; // 讓temp 的原型 等於 this的原型
    f.prototype = new temp(); //f 繼承 temp 聖杯繼承可以瞭解下
    return f;
};

 

先正常執行一下myBind:

  const bind1 = this.out.myBind(my, 50);
    // const bind2 = new bind1('women','myBind');
  const bind3 = bind1('women','myBind');

結果是:

50 "women" 16 "handsome man" "myBind"

OK , 和bind的輸出結果一樣

再使用new操作符:

  const bind1 = this.out.myBind(my, 50);
    const bind2 = new bind1('women','myBind');
    // const bind3 = bind1('women','myBind');

結果是這樣:此時this不再指向my, 而是指向new 出來的一個空對象,所以this上沒有age和sex兩個屬性

50 "women" undefined undefined "myBind"

 

到此bind 我們已經完美模擬出來了  -------- 是不是有點小激動 ----------細心的道友會發現myBind 里 還借用了call 和apply!!! 這還不行啊

 


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

-Advertisement-
Play Games
更多相關文章
  • 一直以來,跨平臺開發都是困擾移動客戶端開發的難題。 在馬蜂窩旅游 App 很多業務場景里,我們嘗試過一些主流的跨平臺開發解決方案, 比如 WebView 和 React Native,來提升開發效率和用戶體驗。但這兩種方式也帶來了新的問題。 比如使用 WebView 跨平臺方式,優點確實非常明顯。基 ...
  • 因為原項目應用的都是v4v7包,谷歌改成androidx後就升級了一番,首先在properties文件 然後在菜單里點擊升級,studio會幫你把報名什麼的都改掉 打開項目,發現都自動改掉了,完美,然而做為一個android開發,我懷疑可能沒有那麼簡單,做好心理準備,我們不能太年輕了,應該成熟點了 ...
  • 基本原理 利用 runtime 原理,獲取模型中所有實例變數列表,根據實例變數以此獲取模型中成員變數的名稱和屬性類型,區分Foundation和自定義屬性,需要對NSDictionary和NSArray類型做單獨處理。 下麵代碼是一個簡單的原理實現Demo,真正的框架中需要考慮很多問題,例如可以設置 ...
  • webpack的常用loder和插件 loder和插件是什麼,現在暫且不表,看到後面你就懂了 引入css問題 直接用link標簽導入css 在前面的講解中,相信已經對webpack有一定瞭解了,相比很多朋友已經躍躍欲試了,準備要搞一個自己的小 ...
  • 因喜歡互聯網這個行業,關註了互聯網和科技大咖,看到了喬布斯曾經說過的一句話就是web就是未來,當時不理解什麼是web上網查詢後得知web是一個職業,不單單是一個技術行業,可以說一門藝術了!後來辭職就開始學習web前端也自學過,報過一些前端班級,可總覺得少了點什麼,因為是零基礎。特別喜歡用代碼來實現一 ...
  • 前言:第一次寫博客有點緊張233333,我會在博客里放一下在賭這本書過程中遇到的一些有用的知識點,希望等幫助到大家。好了正題開始(只要是我不知道該說啥了= =) 一,資源(在w3cfuns資源中可以找到第一版和第二版) 《鋒利的jquery》: http://pan.baidu.com/share/ ...
  • 子傳父 邏輯: 單擊子組件的按鈕 ,觸發它的單擊事件 通過 $emit 觸發父級自定義事件 並傳一個值給父級 1 <div id="id"> 2 3 <h3>兒子 你今年多大了 -- {{age}}</h3> 4 <!-- @getage 自定義事件 --> 5 <con1 @getage='get ...
  • 來自:https://www.cnblogs.com/bluestorm/p/6252900.html 侵刪 git branch(分支命令的使用http://hbiao68.iteye.com/blog/2055493 0.可以通過git branch -r 命令查看遠端庫的分支情況 1,從已有的 ...
一周排行
    -Advertisement-
    Play Games
  • 前言 推薦一款基於.NET 8、WPF、Prism.DryIoc、MVVM設計模式、Blazor以及MySQL資料庫構建的企業級工作流系統的WPF客戶端框架-AIStudio.Wpf.AClient 6.0。 項目介紹 框架採用了 Prism 框架來實現 MVVM 模式,不僅簡化了 MVVM 的典型 ...
  • 先看一下效果吧: 我們直接通過改造一下原版的TreeView來實現上面這個效果 我們先創建一個普通的TreeView 代碼很簡單: <TreeView> <TreeViewItem Header="人事部"/> <TreeViewItem Header="技術部"> <TreeViewItem He ...
  • 1. 生成式 AI 簡介 https://imp.i384100.net/LXYmq3 2. Python 語言 https://imp.i384100.net/5gmXXo 3. 統計和 R https://youtu.be/ANMuuq502rE?si=hw9GT6JVzMhRvBbF 4. 數 ...
  • 本文為大家介紹下.NET解壓/壓縮zip文件。雖然解壓縮不是啥核心技術,但壓縮性能以及進度處理還是需要關註下,針對使用較多的zip開源組件驗證,給大家提供個技術選型參考 之前在《.NET WebSocket高併發通信阻塞問題 - 唐宋元明清2188 - 博客園 (cnblogs.com)》講過,團隊 ...
  • 之前寫過兩篇關於Roslyn源生成器生成源代碼的用例,今天使用Roslyn的代碼修複器CodeFixProvider實現一個cs文件頭部註釋的功能, 代碼修複器會同時涉及到CodeFixProvider和DiagnosticAnalyzer, 實現FileHeaderAnalyzer 首先我們知道修 ...
  • 在軟體行業,經常會聽到一句話“文不如表,表不如圖”說明瞭圖形在軟體應用中的重要性。同樣在WPF開發中,為了程式美觀或者業務需要,經常會用到各種個樣的圖形。今天以一些簡單的小例子,簡述WPF開發中幾何圖形(Geometry)相關內容,僅供學習分享使用,如有不足之處,還請指正。 ...
  • 在 C# 中使用 RabbitMQ 通過簡訊發送重置後的密碼到用戶的手機號上,你可以按照以下步驟進行 1.安裝 RabbitMQ 客戶端庫 首先,確保你已經安裝了 RabbitMQ 客戶端庫。你可以通過 NuGet 包管理器來安裝: dotnet add package RabbitMQ.Clien ...
  • 1.下載 Protocol Buffers 編譯器(protoc) 前往 Protocol Buffers GitHub Releases 頁面。在 "Assets" 下找到適合您系統的壓縮文件,通常為 protoc-{version}-win32.zip 或 protoc-{version}-wi ...
  • 簡介 在現代微服務架構中,服務發現(Service Discovery)是一項關鍵功能。它允許微服務動態地找到彼此,而無需依賴硬編碼的地址。以前如果你搜 .NET Service Discovery,大概率會搜到一大堆 Eureka,Consul 等的文章。現在微軟為我們帶來了一個官方的包:Micr ...
  • ZY樹洞 前言 ZY樹洞是一個基於.NET Core開發的簡單的評論系統,主要用於大家分享自己心中的感悟、經驗、心得、想法等。 好了,不賣關子了,這個項目其實是上班無聊的時候寫的,為什麼要寫這個項目呢?因為我單純的想吐槽一下工作中的不滿而已。 項目介紹 項目很簡單,主要功能就是提供一個簡單的評論系統 ...