工做那麼累,先聽我講個故事:程序員
小李是一名資深程序員,通過多年的磨練已練就了一身紮實的技能,活潑開朗的他不想一直跟冷冰冰的電腦打交道,想從事一些人情味更濃的職業,因此轉行去某團送外賣,畢竟這樣跟客戶接觸的機會多多了 (我瞎說的)。
一天,小李接到附近寫字樓裏的一個外賣訂單,送到客戶 (小白,另外一個程序員)那的時候發現眼前的場景是那麼熟悉:小白正爲解決一個bug急的抓耳撓腮,百思不得其解之時,小李掃了一眼屏幕上的代碼說「你先吃飯,我試試?」,小白一聽,扭過頭來,眼睛都要驚呆了,雙腿一蹬,滑向一邊,給這個「外賣小哥」騰位置……這邊小李噼裏啪啦一頓操做,最後幫小白解決了四處bug,優化了兩個算法,梳理了數據庫的表關係……
小白嘴裏的紅燒肉忽然不香了,小李早已走遠,開始送下一單外賣~
帶着故事,展開咱們今天的主題——call
(apply
的功能和它同樣)。算法
用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()
這樣,該怎麼辦呢?字體
畢竟不是全部外賣員都會編程,在其內部寫編程技能只會顯得不三不四,由於這根本就不符合常理,最好是借用現有的編程方法~
programmer.programming.call(delivery) // 打印結果:外賣員編程 programmer.programming.apply(delivery) // 打印結果:外賣員編程
正如咱們上面講的僞代碼程序員.編程.call(外賣員)
同樣,此時,console.log(
${this.name}編程)
的this指針指向的就是外賣員delivery對象,天然this.name就是delivery.name,即「外賣員」。優化
如今咱們稍微修改一下代碼,看看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()》。