bind、call、apply的區別與用法?

我們在看一些插件的時候,經常會用到這 3 個函數,那麼他們具體的用途是什麼呢?區別又是什麼呢?我們先看看下面一段代碼:

var name = '小白'
var obj = {
	name: '小明',
	getName: function () {
		console.log(this, this.name)
		return this.name
	}
}
var getName = obj.getName
obj.getName()
// obj, 小明
getName()
// window,小白

是不是很神奇,同一個函數,執行的結果不一樣,這裏涉及到一個this的指向問題。

函數中的this指向

js中一個普通函數this的指向與其本身無關,只與調用該函數的對象有關。根據這個規則,我們回到上面的問題,obj.getName調用getName函數的對象是obj,所以this指向了obj對象,那麼得到的obj.name爲小明;而getName()是直接調用的函數,實際上是window.geName()window對象在調用函數,this則指向window對象。(use strict 嚴格模式下,全局 this 是 undefined,而不是window)。
關於this的指向這裏不做具體講解,畢竟這是個複雜的問題,後面再分情況講解,畢竟這也是一個高頻面試題。

bind、call、apply 的作用

這 3 個函數的作用是,改變一個函數在執行時this的指向。我們來改造上面的代碼。

var name = '小白';
var obj = {
	name: '小明',
	getName: function () {
		console.log(this, this.name)
		return this.name
	}
};

var obj1 = {name: '小花'}

var getName = obj.getName;
getName();
// window,小白
obj.getName();
// obj, 小明
getName.apply(obj);
// obj,小明
getName.call(obj1);
// obj1,小花
getName.bind(obj)();
// obj,小明

可以看到,當我們改用apply去調用函數時,不管其所在的作用域,我們的this指向bind,apply,call函數接受的第一個參數。

相同點與不同點

相同點:三個函數都是爲了改變被調用函數的this指向,都指向接受的第一個參數。
不同點:

  1. applycall都是直接調用函數,而bind則是先將函數暫存起來,需要再單獨調用一次。
  2. applycall第一個參數一樣,都是要綁定給 this 的值,如果這個值爲null或者undefined,則爲window對象。他們的區別在第二個參數上:當函數需要傳遞多個變量時, apply可以接受一個數組作爲參數輸入, call 則是接受一系列的單獨變量。當參數個數已知的時候可以用call,而當參數個數不確定的時候可以用apply
  3. bindcall很相似,第一個參數是this的指向,從第二個參數開始是接收的參數列表。區別在於bind方法返回值是函數以及bind接收的參數列表的使用。bind 方法不會立即執行,而是返回一個改變了上下文 this後的函數。而不會影響原函數中的this指向。

最後我們再看一個完整的實例來表現這個三個函數的用途和區別:

function sub(a, b) {
		const sub = a + b
		console.log(sub)
		return sub
	}
	sub.call(null, 1, 2)
	sub.apply(null, [1, 2])
	sub.bind(null, 1, 2)()

可以看到,callapply參數不一樣,而bind參數和call一樣,但還需要單獨調用一下函數。

應用場景

求數組中的最大和最小值
var arr = [0,8,3,46]
var max = Math.max.apply(null,arr);//46
var min = Math.min.apply(null,arr);//0
// 等價於
var max = window.Math.max(...arr);
var min = window.Math.min(...arr);

這裏利用apply的第二個參數是接受一個數組,而在調用函數的時候會自動展開這個數組,而max和min方法接受參數的形式是(1,2,3,4)。

將 arguments 等類數組轉換爲數組
var trueArr = Array.prototype.slice.call(arguments,0,arguments.length)
判斷變量類型
function isArray(obj){
    return Object.prototype.toString.call(obj) == '[object Array]';
}
isArray([]) // true
isArray('dot') // false
使用 log 代替 console.log
function log(){
  console.log.apply(console, arguments);
}

以上用途參考:call、apply 和 bind 方法的用法以及區別

總結

callapplybind都是爲了改變當前要執行函數this指向,由第一個參數決定,爲null或者undefined時則爲window對象。callapply的參數有區別。而bind不是馬上執行函數,而是返回該函數和保留該函數的執行上下文。

學習如逆水行舟,不進則退,前端技術飛速發展,如果每天不堅持學習,就會跟不上,我會陪着大家,每天堅持推送博文,跟大家一同進步,希望大家能關注我,第一時間收到最新文章。

個人公衆號:長按保存關注

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