自己動手用原生實現 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 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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...