詳解 JS 函數(shù)的 call局装、apply 及 bind 方法

??總結(jié)

  1. 相同點(diǎn)
    • 都能夠改變目標(biāo)函數(shù)執(zhí)行時(shí)內(nèi)部 this 的指向
    • 方法的第一個(gè)參數(shù)用于指定函數(shù)執(zhí)行時(shí)內(nèi)部的 this 值
    • 支持向目標(biāo)函數(shù)傳遞任意個(gè)參數(shù)
    • 若不向方法的第一個(gè)參數(shù)傳值或者傳遞 undefined冀偶、null闲延,則在 JavaScript 正常模式下姆涩,目標(biāo)函數(shù)內(nèi)部的 this 指向 window 對(duì)象污茵,嚴(yán)格模式下,分別指向 undefined蝙昙、null闪萄。
  2. 區(qū)別
    • apply() 方法可接收兩個(gè)參數(shù),而 call()bind() 方法則可接收多個(gè)參數(shù)奇颠。
    • apply() 方法向目標(biāo)函數(shù)傳遞參數(shù)時(shí)只需將參數(shù)數(shù)組arguments 對(duì)象作為方法的第二個(gè)參數(shù)即可败去,而 call()bind() 方法則需要將傳參逐個(gè)列舉在方法的一個(gè)參數(shù)后面。
    • 調(diào)用 call()apply() 方法時(shí)會(huì)立即執(zhí)行目標(biāo)函數(shù)烈拒,而 bind() 方法則不會(huì)圆裕,它將返回一個(gè)新函數(shù)——目標(biāo)函數(shù)的拷貝,該函數(shù)內(nèi)部的 this 指向 bind() 方法的第一個(gè)參數(shù)荆几,之后執(zhí)行新函數(shù)相當(dāng)于執(zhí)行了目標(biāo)函數(shù)吓妆。
    • 只有 bind() 方法實(shí)現(xiàn)了函數(shù)柯里化,因此可以分兩次向目標(biāo)函數(shù)傳遞參數(shù)吨铸。

call() 方法

  1. 調(diào)用 call() 方法會(huì)立即執(zhí)行目標(biāo)函數(shù)行拢,同時(shí)改變函數(shù)內(nèi)部 this 的指向。this 指向由方法的第一個(gè)參數(shù)決定诞吱,后面逐個(gè)列舉的任意個(gè)參數(shù)將作為目標(biāo)函數(shù)的參數(shù)一一對(duì)應(yīng)傳入舟奠。

  2. 對(duì)于開頭總結(jié)中相同點(diǎn)的最后一點(diǎn)竭缝,示例如下:

    /* 正常模式 */
    
    let obj = {
      sum(a, b) {
        console.log(this)
        return a + b
      }
    }
    
    // 執(zhí)行 sum 函數(shù)的 apply、bind 方法沼瘫,打印的 this 同下
    obj.sum.call()  // 打印 window
    obj.sum.call(undefined, 1, 2)  // 打印 window
    obj.sum.call(null, 1, 2)  // 打印 window
    
    /* 嚴(yán)格模式 */
    'use strict'
    
    // 執(zhí)行 sum 函數(shù)的 apply抬纸、bind 方法,打印的 this 同下
    obj.sum.call()  // 打印 undefined
    obj.sum.call(undefined, 1, 2)  // 打印 undefined
    obj.sum.call(null, 1, 2)  // 打印 null
    

模擬實(shí)現(xiàn)

  1. 關(guān)鍵點(diǎn)

    • myCall() 方法被添加在 Function 原型對(duì)象上耿戚,目標(biāo)函數(shù)調(diào)用該方法時(shí)湿故,myCall() 方法內(nèi)部的 this 將指向目標(biāo)函數(shù)。
    • 將目標(biāo)函數(shù)作為 context 對(duì)象的方法來(lái)執(zhí)行膜蛔,由此目標(biāo)函數(shù)內(nèi)部的 this 將指向 context 對(duì)象晓锻。
    • 從 context 對(duì)象中刪除目標(biāo)函數(shù)
    • 使用擴(kuò)展運(yùn)算符 ... 處理傳入目標(biāo)函數(shù)的參數(shù)
  2. call()、apply()飞几、bind() 方法的模擬實(shí)現(xiàn)中砚哆,對(duì)于不傳第一個(gè)參數(shù)或者傳遞 undefined、null 時(shí)屑墨,這里在 JS 正常模式和嚴(yán)格模式下做了統(tǒng)一處理躁锁,即目標(biāo)函數(shù)內(nèi)部的 this 均指向 window 對(duì)象。

  3. 代碼如下

    Function.prototype.myCall = function (context, ...args) {
      if (context === undefined || context === null) {
        context = window
      }
      // 下面這行為核心代碼
      context.fn = this
      const result = context.fn(...args)
      delete context.fn
      return result
    }
    
    let obj1 = {
      basicNum: 1,
      sum(a, b) {
        console.log(this)
        return this.basicNum + a + b
      }
    }
    let obj2 = {
      basicNum: 9
    }
    console.log(obj1.sum.call(obj2, 2, 3))  // 14
    console.log(obj1.sum.myCall(obj2, 2, 3))  // 14
    

apply() 方法

調(diào)用 apply() 方法會(huì)立即執(zhí)行目標(biāo)函數(shù)卵史,同時(shí)改變函數(shù)內(nèi)部 this 的指向战转。this 指向由方法的第一個(gè)參數(shù)決定,第二個(gè)參數(shù)是一個(gè)參數(shù)數(shù)組arguments 對(duì)象以躯,各數(shù)組元素或 arguments 對(duì)象表示的各參數(shù)將作為目標(biāo)函數(shù)的參數(shù)一一對(duì)應(yīng)傳入槐秧。

模擬實(shí)現(xiàn)

  1. 關(guān)鍵點(diǎn)

    • myApply() 方法被添加在 Function 原型對(duì)象上,目標(biāo)函數(shù)調(diào)用該方法時(shí)忧设,myApply() 方法內(nèi)部的 this 將指向目標(biāo)函數(shù)刁标。
    • 將目標(biāo)函數(shù)作為 context 對(duì)象的方法來(lái)執(zhí)行,由此目標(biāo)函數(shù)內(nèi)部的 this 將指向 context 對(duì)象址晕。
    • 從 context 對(duì)象中刪除目標(biāo)函數(shù)
    • 使用擴(kuò)展運(yùn)算符 ... 處理傳入目標(biāo)函數(shù)的參數(shù)
  2. 代碼如下

    Function.prototype.myApply = function (context, args) {
      if (context === undefined || context === null) {
        context = window
      }
      // 下面這行為核心代碼
      context.fn = this
      const result = context.fn(...args)
      delete context.fn
      return result
    }
    
    console.log(obj1.sum.apply(obj2, [2, 3]))  // 14
    console.log(obj1.sum.myApply(obj2, [2, 3]))  // 14
    

bind() 方法

  1. 調(diào)用 bind() 方法將返回一個(gè)新函數(shù)——目標(biāo)函數(shù)的拷貝膀懈,該函數(shù)內(nèi)部的 this 指向方法的第一個(gè)參數(shù),后面逐個(gè)列舉的任意個(gè)參數(shù)將作為目標(biāo)函數(shù)的參數(shù)一一對(duì)應(yīng)傳入谨垃。之后執(zhí)行新函數(shù)相當(dāng)于執(zhí)行了目標(biāo)函數(shù)启搂。
  2. bind() 方法實(shí)現(xiàn)了函數(shù)柯里化,因此可以分兩次向目標(biāo)函數(shù)傳遞參數(shù)刘陶,第一次的參數(shù)列舉在 bind() 方法首參后面胳赌,第二次的參數(shù)列舉在新函數(shù)中。

模擬實(shí)現(xiàn)

  1. 關(guān)鍵點(diǎn)

    • myBind() 方法被添加在 Function 原型對(duì)象上匙隔,目標(biāo)函數(shù)調(diào)用該方法時(shí)疑苫,myBind() 方法內(nèi)部的 this 將指向目標(biāo)函數(shù)。
    • 將目標(biāo)函數(shù)作為 context 對(duì)象的方法來(lái)執(zhí)行,由此目標(biāo)函數(shù)內(nèi)部的 this 將指向 context 對(duì)象缀匕。
    • 從 context 對(duì)象中刪除目標(biāo)函數(shù)
    • 使用擴(kuò)展運(yùn)算符 ... 處理傳入目標(biāo)函數(shù)的初始參數(shù)笼痛、后續(xù)參數(shù)贺嫂。
  2. 代碼如下

    Function.prototype.myBind = function (context, ...initArgs) {
      if (context === undefined || context === null) {
        context = window
      }
      // 緩存 this 值
      const _this = this
      return function (...args) {
        // 下面這行為核心代碼
        context.fn = _this
        const result = context.fn(...initArgs, ...args)
        delete context.fn
        return result
      }
    }
    
    console.log(obj1.sum.bind(obj2, 2)(3))  // 14
    console.log(obj1.sum.myBind(obj2, 2)(3))  // 14
    

??相關(guān)知識(shí)點(diǎn)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市奢啥,隨后出現(xiàn)的幾起案子饵史,更是在濱河造成了極大的恐慌满钟,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,723評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件胳喷,死亡現(xiàn)場(chǎng)離奇詭異湃番,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)吭露,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門吠撮,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人讲竿,你說(shuō)我怎么就攤上這事泥兰。” “怎么了题禀?”我有些...
    開封第一講書人閱讀 152,998評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵鞋诗,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我迈嘹,道長(zhǎng)削彬,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,323評(píng)論 1 279
  • 正文 為了忘掉前任秀仲,我火速辦了婚禮融痛,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘神僵。我一直安慰自己酌心,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,355評(píng)論 5 374
  • 文/花漫 我一把揭開白布挑豌。 她就那樣靜靜地躺著安券,像睡著了一般。 火紅的嫁衣襯著肌膚如雪氓英。 梳的紋絲不亂的頭發(fā)上侯勉,一...
    開封第一講書人閱讀 49,079評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音铝阐,去河邊找鬼址貌。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的练对。 我是一名探鬼主播遍蟋,決...
    沈念sama閱讀 38,389評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼螟凭!你這毒婦竟也來(lái)了虚青?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,019評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤螺男,失蹤者是張志新(化名)和其女友劉穎棒厘,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體下隧,經(jīng)...
    沈念sama閱讀 43,519評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡奢人,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,971評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了淆院。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片何乎。...
    茶點(diǎn)故事閱讀 38,100評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖土辩,靈堂內(nèi)的尸體忽然破棺而出支救,到底是詐尸還是另有隱情,我是刑警寧澤脯燃,帶...
    沈念sama閱讀 33,738評(píng)論 4 324
  • 正文 年R本政府宣布搂妻,位于F島的核電站,受9級(jí)特大地震影響辕棚,放射性物質(zhì)發(fā)生泄漏欲主。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,293評(píng)論 3 307
  • 文/蒙蒙 一逝嚎、第九天 我趴在偏房一處隱蔽的房頂上張望扁瓢。 院中可真熱鬧,春花似錦补君、人聲如沸引几。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,289評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)伟桅。三九已至,卻和暖如春叽掘,著一層夾襖步出監(jiān)牢的瞬間楣铁,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,517評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工更扁, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留盖腕,地道東北人赫冬。 一個(gè)月前我還...
    沈念sama閱讀 45,547評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像溃列,于是被迫代替她去往敵國(guó)和親劲厌。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,834評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容