今天咱們來講一下call、apply、bind這三兄弟的功能和區別順便本身封裝一下es6
~~無論是call、apply仍是bind做用都是爲了改變函數中this的指向 ,因此他們的做用實際上是大同小異滴! 先說call 舉個例子吧數組
function fn() {
console.log(arguments)
console.log(this)
}
var obj = {
f: fn
}
複製代碼
就說他吧你要是運行個fn.call(obj, 4, 4, 4)
這個 按理說this應該指向'點'前邊的那位,可是呢我們用了call那可就不同了,this就會指向call後邊括號裏第一個參數,固然首先我們得保證那個函數不能是箭頭函數,箭頭函數嘛 無論咋樣this都指向他的上級,由此還得出一個結論 this的指向的權重!!! ---箭頭函數 > call(apply,bind)這三兄弟 >"點" 而後括號中除了第一個參數以外剩下的都是 傳進去的參數
=====總之括號裏:bash
」第一個參數用函數執行時this的指向 後邊的參數都是傳給前邊函數的實參「app
fn.call(obj, 4, 4, 4)
他的結果就是4,4,4和obj了!函數
~~對了奧call apply bind 這三兄弟 都是存在Function的原型裏邊的,我想在座的各位應該都知道吧! 既然他存在在Function的原型裏邊 咱們不如 ? 嘿嘿嘿本身封裝一個? 說封就封!淦!ui
封裝以前加個小插曲es6中的...是剩餘運算符this
let a = ['apple','banana','orange'];
console.log(...a); //apple, banana, orange
複製代碼
就這麼用的!!spa
開始封裝!!prototype
Function.prototype.myCall = function (context, ...ary) {
var key = Symbol()
context[key] = this
context[key](...ary)
delete context[key]
}
fn.myCall(obj, 6, 6, 6)
複製代碼
就這點代碼就ok了 context是他的形參也就是咱們須要讓this指向的地方 ...ary是解構了除了第一項以後的實參code
//怎麼保證一個函數執行上下文是context context.qqq()
qqq執行時裏邊的 this就是context 可是呢這個qqq頗有可能會和實參裏邊的屬性重複因此咱們用了Symbol這個東西他就是一個惟一的東西 就不會重複啦爲啥還要把他刪了呢
delete context[key]
由於這樣咱們會在實參obj中加一個新的屬性 因此爲了避免改變他就再刪掉他
雖然封裝一個功能和call相同的函數像是在白白費力,明明用call就能夠解決咱們還封裝,沒事找個樂子嘛!也鍛鍊鍛鍊腦殼!
~~爲啥說他三是三兄弟其實他們三真的很像 apply似於call 可是第二個參數是一個集合 (數組或者類數組),
fn.apply(obj, [6, 6, 6])
和call同樣同樣的 就是後邊參數必須得是數組或者類數組,也就是說呀他傳進去以後會自動把這個數組或者類數組散開,和call好像啊!因此奧老二就介紹到這裏了 哈哈哈哈!
~~這三兄弟是否是三胞胎?bind的用法和call 如出一轍 只是否是讓函數當即執行的而是返回一個新函數,新函數執行時 ,裏邊的this 會改變成 指定的對象
看個小例子吧:
var fn2 = fn.bind(obj, 6, 6, 6)
fn2()
複製代碼
讓fn執行而且把fn中的this 改爲了obj,還把6,6,6傳給了fn 就是呀新函數執行後他的this纔會變其餘和call是同樣滴
我們再封裝個本身的bind?
淦!來 !fn我們還用上邊的奧 就不寫了
Function.prototype.myBind = function (context, ...arg) {
var _this = this
return function (...ary) {
_this.call(context, ...arg)
}
}
複製代碼
注意奧var _this=this
就是存儲的就是fn函數 其實呀就是讓call的返回值再加一步函數這樣就可讓他運行以後他再讓this指向我們第一項的參數了
還有一個簡單的方法:
Function.prototype.myBind=function(context,...arg){
return(...ary)=>{
this.call(context,...arg,...ary)
}
}
複製代碼
其實和上邊意思是同樣的 就是換成了箭頭函數this就本身找他去了