一文讀懂js中的call和apply

工做那麼累,先聽我講個故事:程序員

小李是一名資深程序員,通過多年的磨練已練就了一身紮實的技能,活潑開朗的他不想一直跟冷冰冰的電腦打交道,想從事一些人情味更濃的職業,因此轉行去某團送外賣,畢竟這樣跟客戶接觸的機會多多了 我瞎說的)。
一天,小李接到附近寫字樓裏的一個外賣訂單,送到客戶 (小白,另外一個程序員)那的時候發現眼前的場景是那麼熟悉:小白正爲解決一個bug急的抓耳撓腮,百思不得其解之時,小李掃了一眼屏幕上的代碼說「你先吃飯,我試試?」,小白一聽,扭過頭來,眼睛都要驚呆了,雙腿一蹬,滑向一邊,給這個「外賣小哥」騰位置……這邊小李噼裏啪啦一頓操做,最後幫小白解決了四處bug,優化了兩個算法,梳理了數據庫的表關係……
小白嘴裏的紅燒肉忽然不香了,小李早已走遠,開始送下一單外賣~

帶着故事,展開咱們今天的主題——callapply的功能和它同樣)。算法

用call的思想總結上面的劇情:程序員.編程.call(外賣員)數據庫

翻譯的直白一點就是:外賣員小李借用程序員的編程技能幫小白解決了bug,即外賣員編程編程

外賣小哥還有別的才藝,對應的call思想僞代碼以下:
「外賣員炒菜」:廚師.炒菜.call(外賣員)
「外賣員彈鋼琴」:演奏家.彈鋼琴.call(外賣員)
「外賣員換輪胎」:修理工.換輪胎.call(外賣員)……數組

幫助記憶:對於 程序員.編程.call(外賣員),call能夠字面理解爲「打電話」—— 程序員(擁有 編程技能) 打電話告訴 外賣員怎麼敲代碼(注意四個加粗字體的順序)。

場景帶入

下面看一段代碼,定義程序員、外賣員對象,對象屬性包含各自的名稱和技能:app

// 定義程序員對象
var programmer = {
  name: '程序員',
  programming: function () {
    console.log(`${this.name}編程`)
  }
}

// 定義外賣員對象
var delivery = {
  name: '外賣員',
  sendFood: function () {
    console.log(`${this.name}送餐`)
  }
}

程序員編程:programmer.programming()
外賣員送餐:delivery.sendFood()
都再正常不過,屬於自然屬性。函數

但若是想讓外賣員編程,又不想給外賣員額外寫個編程方法,就像:delivery.programming()這樣,該怎麼辦呢?字體

畢竟不是全部外賣員都會編程,在其內部寫編程技能只會顯得不三不四,由於這根本就不符合常理,最好是借用現有的編程方法~

call閃耀登場

programmer.programming.call(delivery) // 打印結果:外賣員編程

programmer.programming.apply(delivery) // 打印結果:外賣員編程

正如咱們上面講的僞代碼程序員.編程.call(外賣員)同樣,此時,console.log(${this.name}編程)的this指針指向的就是外賣員delivery對象,天然this.name就是delivery.name,即「外賣員」。優化

call/apply傳參

如今咱們稍微修改一下代碼,看看call和apply如何傳參:this

// 定義程序員對象
var programmer = {
  name: '程序員',

  // 改動1:新增三個形參
  programming: function (ability1, ability2, ability3) {
    console.log(`${this.name}編程`)

    // 改動2:新增打印
    console.log(`更多技能:${ability1}、${ability2}、${ability3}`)
  }
}
programmer.programming.call(delivery, '炒菜', '彈鋼琴', '換輪胎')

// 注意apply的傳參方式:數組形式
programmer.programming.apply(delivery, ['炒菜', '彈鋼琴', '換輪胎'])

// 兩者打印結果皆爲:
// 外賣員編程
// 更多技能:炒菜、彈鋼琴、換輪胎

總結

call和apply的做用都是改變this做用域,都是在特定做用域中調用函數。當一個對象沒有某個方法,而其餘對象有,咱們就可使用call或apply實現某個方法的複用。

call和apply使用方法基本相同,惟一不一樣之處就是它們的參數規則:call方法接受一個參數列表,而apply方法接受一個包含多個參數的數組


12月20日補充:

call和apply在開發中的使用場景見《理解Array.prototype.slice.call()》

相關文章
相關標籤/搜索