一行代碼看懂bind,call

代碼

var slice = Function.prototype.call.bind(Array.prototype.slice);

slice() 方法返回一個新的數組對象(原數組的淺拷貝),常用於動態解析參數。看過MDN的童鞋,對這行代碼不會陌生。MDN上的描述比較官方,下面我們通過對這行代碼的知識點的逐一分析來加深理解。

Function.prototype.call

call :臨時性的改變一個函數的this。原本函數是誰調用,this就指向誰。call是通過第一個參數,告訴函數本次調用者另有其人,然後接着傳入參數:

fun.call(thisArg, arg1, arg2, ...)

測試demo:

function testCall(){console.log(this)}
testCall()
//Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, parent: Window, …}
testCall.call({})
//{}
testCall()
//Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, parent: Window, …}

Function.prototype.bind

bind:創建一個新的函數,新函數的this永久指向第一個參數:

fun.bind(thisArg[, arg1[, arg2[, ...]]])

測試demo:

var t={testBind(){console.log(this)}}
t.testBind()
//{testBind: ƒ}
t.testBind2=t.testBind.bind({x:1})
t.testBind2()
//{x: 1} 雖然調用的還是t,但是this指向的還是bind的
t.testBind()
//{testBind: ƒ, testBind2: ƒ}
t.testBind2===t.testBind
//false

使用bind去創建的新函數的頻次並不高,筆者表示從沒用到過~
實用一點的是MDN上介紹的偏函數,即使函數預設參數:

//來源MDN
function list() {
  return Array.prototype.slice.call(arguments);
}

var list1 = list(1, 2, 3); // [1, 2, 3]

// Create a function with a preset leading argument
var leadingThirtysevenList = list.bind(undefined, 37);

var list2 = leadingThirtysevenList(); // [37]
var list3 = leadingThirtysevenList(1, 2, 3); // [37, 1, 2, 3]

var leadingThirtysevenList = list.bind(undefined, 37,38,39,40);
leadingThirtysevenList();//[37, 38, 39, 40]
leadingThirtysevenList(1,2,3);//[37, 38, 39, 40, 1, 2, 3]

另外一個實用的地方就是文章開頭寫的快捷調用了:

var slice = Function.prototype.call.bind(Array.prototype.slice);

經過前面的瞭解,我們再來分析下這段代碼:
使用bindcall函數的this永久綁定Array.prototype.slice函數,返回一個新的call函數,我們打印一下:

slice
// ƒ call() { [native code] }

slice({length:1})等價於Array.prototype.slice.call({length:1}),也就是說創建的slicecall 函數的一個變體,是call 函數的一個變體,是call 函數的一個變體。所以筆者覺得,從理解角度來看,新創建的函數slice 命名爲newCall更便於理解。

總結

乍一看,newCallslice函數有點繞,一經推敲還是很好理解的。由此我們也可以寫出來更多的newCall(快捷調用),例如精確類型判斷需要用到的toString

var toString=Function.prototype.call.bind(Object.prototype.toString)
toString({})
//"[object Object]"
toString(1)
//"[object Number]"
toString(null)
//"[object Null]"
toString()
//"[object Undefined]"
toString(false)
//"[object Boolean]"
toString(function(){})
//"[object Function]"

MDN文檔:

MDN-call
MDN-bind
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章