我們在看一些插件的時候,經常會用到這 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
指向,都指向接受的第一個參數。
不同點:
apply
和call
都是直接調用函數,而bind
則是先將函數暫存起來,需要再單獨調用一次。apply
和call
第一個參數一樣,都是要綁定給 this 的值,如果這個值爲null
或者undefined
,則爲window
對象。他們的區別在第二個參數上:當函數需要傳遞多個變量時,apply
可以接受一個數組作爲參數輸入,call
則是接受一系列的單獨變量。當參數個數已知的時候可以用call
,而當參數個數不確定的時候可以用apply
。bind
和call
很相似,第一個參數是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)()
可以看到,call
和apply
參數不一樣,而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 方法的用法以及區別
總結
call
、apply
、bind
都是爲了改變當前要執行函數this
指向,由第一個參數決定,爲null
或者undefined
時則爲window
對象。call
和apply
的參數有區別。而bind
不是馬上執行函數,而是返回該函數和保留該函數的執行上下文。
學習如逆水行舟,不進則退,前端技術飛速發展,如果每天不堅持學習,就會跟不上,我會陪着大家,每天堅持推送博文,跟大家一同進步,希望大家能關注我,第一時間收到最新文章。
個人公衆號: