apply()、call()和bind()方法都是Function.prototype物件中的方法,而所有的函式都是Function的例項。三者都可以改變this的指向,將函式繫結到上下文中。
1. 語法
1.1 Function.prototype.apply()
apply() 方法呼叫一個函式, 其具有一個指定的this值,以及作為一個陣列(或類似陣列的物件)提供的引數。 語法 func.apply(thisArg, [argsArray])
1.2 Function.prototype.call()
call() 方法呼叫一個函式, 其具有一個指定的this值和分別地提供的引數(引數的列表)。 語法 fun.call(thisArg, arg1, arg2, ...)
1.3 Function.prototype.bind()
bind()方法建立一個新的函式, 當被呼叫時,將其this關鍵字設定為提供的值,在呼叫新函式時,在任何提供之前提供一個給定的引數序列。 語法 fun.bind(thisArg, 佇列or陣列)()
2. 用法
這三個方法的用法非常相似,將函式繫結到上下文中,即用來改變函式中this的指向。
2.1 普通寫法
let me = {
name: "me",
sayHello: function (age) {
console.log("hello, I am", this.name + " " + age + " " + "years old")
}
}
let someone = {
name: "someone",
}
me.sayHello(24) // hello, I am me 24 years old
複製程式碼
2.2 call 與apply方法的用法
me.sayHello.apply(someone, [24]) // hello, I am someone 24 years old
me.sayHello.call(someone, 24) // hello, I am someone 24 years old
複製程式碼
結果相同,call()和apply(),第一個引數都是要繫結上下文,後面的引數是要傳遞給呼叫該方法的函式的。不同之處在於,在給呼叫函式傳遞引數時,apply()是陣列,call()引數是逐個列出的。
2.3 bind()的用法
me.sayHello.bind(someone, 24)() // hello, I am someone 24 years old
me.sayHello.bind(someone, ([24])() // hello, I am someone 24 years old
複製程式碼
bind方法傳遞給呼叫函式的引數可以逐個列出,也可以寫在陣列中。bind方法與call、apply最大的不同就是前者返回一個繫結上下文的函式,而後兩者是直接執行了函式。因此,以上程式碼也可以這樣寫:
me.sayHello.bind(someone)(24) // hello, I am someone 24 years old
me.sayHello.bind(someone)([24]) // hello, I am someone 24 years old
複製程式碼
總結bind()的用法:該方法建立一個新函式,稱為繫結函式,繫結函式會以建立它時傳入bind()的第一個引數作為this,傳入bind()的第二個以及以後的引數加上繫結函式執行時本身的引數按照順序作為原函式的引數來呼叫原函式。
3. 應用場景
3.1 求陣列中的最大和最小值
let arr = [1,2,3,89,46]
let max = Math.max.apply(null,arr)//89
let min = Math.min.apply(null,arr)//1
複製程式碼
3.2將類陣列轉化為陣列
let trueArr = Array.prototype.slice.call(arrayLike)
複製程式碼
3.3 陣列追加
let arr1 = [1,2,3]
let arr2 = [4,5,6]
let total = [].push.apply(arr1, arr2) //6
// arr1 [1, 2, 3, 4, 5, 6]
// arr2 [4,5,6]
複製程式碼
3.4 判斷變數型別
function isArray(obj){
return Object.prototype.toString.call(obj) == '[object Array]'
}
isArray([]) // true
isArray('dot') // false
複製程式碼
3.5 利用call和apply做繼承
function Person(name,age){
// 這裡的this都指向例項
this.name = name
this.age = age
this.sayAge = function(){
console.log(this.age)
}
}
function Female(){
Person.apply(this,arguments)//將父元素所有方法在這裡執行一遍就繼承了
}
let dot = new Female('Dot',2)
複製程式碼
3.6 使用 log 代理 console.log
function log(){
console.log.apply(console, arguments);
}
// 當然也有更方便的 let log = console.log()
複製程式碼
4. 總結
- (1).三者都可以改變函式的this物件指向。
- (2).三者第一個引數都是this要指向的物件,如果如果沒有這個引數,預設指向全域性window。
- (3).三者都可以傳參,但是apply是陣列,而call是有順序的傳入。
- (4).bind 是返回對應函式,便於稍後呼叫;apply 、call 則是立即執行 。
5. 參考連結
- https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/apply
- https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/call
- https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/bind
- https://www.jianshu.com/p/bc541afad6ee
- https://www.cnblogs.com/xljzlw/p/3775162.html