![你真的瞭解bind嗎](https://guizimo.oss-cn-shanghai.aliyuncs.com/img/%E4%BD%A0%E7%9C%9F%E7%9A%84%E4%BA%86%E8%A7%A3bind%E5%90%97.png) # 引言 ## 內容速遞 > 看了本文您能瞭解 ...
引言
內容速遞
看了本文您能瞭解到的知識!
在本篇文章中,將帶你瞭解什麼是bind,bind的用途、如何手寫bind以及工作中實際使用bind的場景。
在JavaScript中,bind()
方法是用來創建一個新函數,並將其綁定到指定的對象上,從而在調用該函數時確保函數中的this
關鍵字指向綁定的對象。
1、什麼是bind
bind()
方法創建一個新的函數,在bind()被調用時,這個新函數的this
被指定 bind()
的第一個參數,而其餘參數將作為新函數的參數,供調用時使用。
2、bind的語法
語法:
function.bind(thisArg[, arg1[, arg2[, ...]]])
參數:
-
thisArg:被綁定到函數上的對象,即當調用綁定後的函數時,函數中的
this
關鍵字會指向該對象。如果thisArg
參數為null
或undefined
,則this
關鍵字將指向全局對象(在瀏覽器中通常是window
對象)。 -
arg1, arg2, ...:要傳遞給函數的參數。這些參數將按照順序傳遞給函數,併在調用函數時作為函數參數使用。
返回值:
返回一個原函數的拷貝,並擁有指定的this
值和初始參數。
3、淺試一下bind
代碼:
this.name = 'guizimo'
let obj = {
name: 'zimo',
getName: function() {return this.name}
}
console.log(obj.getName()) // zimo
let newGetName = obj.getName
console.log(newGetName()) // guizimo
let bindGetName = newGetName.bind(obj)
console.log(bindGetName()) // zimo
簡述代碼:
-
第一次列印
zimo
,可以理解為是列印對象內的一個屬性,此時的this
是指向obj對象
。 -
第二次列印
guizimo
,因為當前環境是對象外,因為當前執行的函數是newGetName()
,因此函數內部的this
指向全局對象。 -
通過
bind
生成一個新的拷貝函數,當前執行的函數bindGetName()
的this
指向obj對象
。
4、手寫bind
這是面試官最喜歡的環節了
思路:
bind()
方法返回一個新函數,因此需要定義一個函數來返回新函數。- 在新函數中,需要使用
apply()
或call()
方法來調用原始函數並傳遞正確的this
值和參數。 - 新函數需要接受一個
thisArg
參數來指定要綁定的對象,並可以接受任意數量的其他參數。
代碼:
/**
* 手寫bind
* @returns {function(): any}
*/
Function.prototype.myBind = function () {
// 處理函數
let args = Array.from(arguments);
let thisArg = args.shift();
// 暫存this
let thisFunc = this;
// 因為需要構造函數,所以不能是匿名函數了
const fBound = function () {
const newArgs = args.concat(Array.from(arguments));
// 判斷是否為構造函數
thisArg = this instanceof fBound ? this : thisArg;
return thisFunc.apply(thisArg, newArgs);
}
// 直接將原函數的prototype賦值給綁定函數
fBound.prototype = this.prototype;
// 返回
return fBound;
}
簡述代碼:
- 通過
Array.from()
將arguments
轉化為數組對象,通過shift()
取出thisArg
。 - 使用
thisFunc
暫存當前函數的this
。 - 創建一個閉包函數
fBound
,newArgs
接收合併處理的arguments
。 - 判斷
fBound
是否為構造函數,如果是構造函數,返回閉包的this
,反之,返回外部拿到的thisArg
,使用thisArg
來接收。 - 使用
thisFunc.apply
傳遞thisArg
值和參數newArgs
。 - 直接將原函數的
prototype
賦值給fBound
。 - 返回
fBound
。
5、使用場景
5.1、創建綁定函數
這是bind
最基本的一種使用方式了,也就是創建一個新的函數。
代碼:
this.name = 'guizimo'
let obj = {
name: 'zimo',
getName: function() {return this.name}
}
console.log(obj.getName()) // zimo
let newGetName = obj.getName
console.log(newGetName()) // guizimo
let bindGetName = newGetName.bind(obj)
console.log(bindGetName()) // zimo
簡述代碼:
- 第一次列印
zimo
,可以理解為是列印對象內的一個屬性,此時的this
是指向obj對象
。 - 第二次列印
guizimo
,因為當前環境是對象外,因為當前執行的函數是newGetName()
,因此函數內部的this
指向全局對象。 - 通過
bind
生成一個新的拷貝函數,當前執行的函數bindGetName()
的this
指向obj對象
。
5.2、創建偏函數
如果需要創建一個自定義函數,需要固定部分參數,那麼bind
就有它獨特的作用了
代碼:
function add (a, b) {
return a + b
}
const res1 = add(1, 2)
console.log(res1) // 3
// 創建一個偏函數,將1作為預設的參數
const addP = add.bind(null, 1)
const res2 = addP(2)
console.log(res2) // 3
const res3 = addP(3)
console.log(res3) // 4
const res4 = addP(4)
console.log(res4) // 5
簡述代碼:
- 創建了一個
add
函數,調用add(1, 2)
,正常列印3
。 - 創建一個偏函數
addP
,將1作為預設的參數,調用addP(2)
,也可以正常列印3
,後續調用addP(3)
、addp(4)
,皆列印正確的數值,實現了對一個參數的固定。
6、在工作中有遇到bind的使用場景嗎
6.1、React中bind的場景
在JSX
中傳遞的事件不是一個字元串,而是一個函數(如:onClick={this.handleClick}
),此時onClick
即是中間變數,所以處理函數中的this指向
會丟失。
代碼:
<button onClick={this.handleClick.bind(this)}>點擊</button>
//此時this指向是當前實例對象
handleAdd = () => {
console.log(this)
this.setState({
...
})
}
解決這個問題就是給調用函數時bind(this)
,從而使得無論事件處理函數如何傳遞,this指向
都是當前實例化對象。或者使用箭頭函數聲明一個函數,這樣函數內的this
也是指向當前實例。
6.2、在事件處理程式中訪問事件目標的this值
在JavaScript中,需要在事件處理程式中訪問事件目標的this
值。在這種情況下,可以使用bind()
方法將事件處理程式綁定到事件目標上,以便在調用事件處理程式時,this
關鍵字始終指向事件目標。
代碼:
const button = document.querySelector('#myButton');
button.addEventListener('click', function() {
// 在這裡可以使用 this 訪問按鈕元素的屬性和方法
}.bind(button));
博客說明與致謝
文章所涉及的部分資料來自互聯網整理,其中包含自己個人的總結和看法,分享的目的在於共建社區和鞏固自己。
引用的資料如有侵權,請聯繫本人刪除!
感謝勤勞的自己,個人博客,GitHub,公眾號【歸子莫】,小程式【子莫說】
如果你感覺對你有幫助的話,不妨給我點贊鼓勵一下,好文記得收藏喲!
幸好我在,感謝你來!