JavaScript中apply和bind的关系
2015-09-18
apply 和 call
每个函数都包含两个非继承而来的方法:apply()
和call()
。这两个方法的用途都是在特定的作用域内调用函数,实际上等于设置函数体内this
对象的值。其中call()
本质上是apply()
的语法糖,在参数少于 3 个时使用call()
更简洁。
apply
apply()
方法接收两个参数,一是在其中运行函数的作用域,另一个是参数数组。其中,第二个参数既可以是 Array 实例,也可以是 arguments 对象。
function sum(num1, num2) {
return num1 + num2
}
function applySum1(num1, num2) {
return sum.apply(this, arguments)
}
function applySum2(num1, num2) {
return sum.apply(this, [num1, num2])
}
console.log(applySum1(10, 20)) // 30
console.log(applySum2(10, 20)) // 30
call
call()
方法与apply()
方法作用相同,它们的区别主要在于接收参数的方式不同。对于call()
方法而言,第一个参数不变,第二个参数变成将传递给函数的参数逐个列举。
function sum(num1, num2) {
return num1 + num2
}
function callSum(num1, num2) {
return sum.call(this, num1, num2)
}
bind
通过使用apply()
和call()
,可以极为方便的扩展函数作用域:
window.color = 'red'
var o = {
color: 'blue',
sayColor: function() {
console.log(this.color)
},
}
function sayColor() {
console.log(this.color)
}
sayColor.call(this) // red
sayColor.call(window) // red
sayColor.call(o) // blue
o.sayColor() // blue
身为 JavaScript 中的一等公民,函数可以作为结果返回。这个特点使得用现有函数构造新函数成为可能:
var o = {
color: 'blue',
}
function sayColor() {
console.log(this.color)
}
o.sayColor = function() {
return sayColor.apply(this)
}
o.sayColor() // blue
将这种操作封装,便有了bind()
方法:
if (typeof Function.prototype.bind !== 'function') {
Function.prototype.bind = function(scope) {
var fn = this,
slice = Array.prototype.slice,
args = slice.apply(arguments, [1])
return function() {
return fn.apply(scope, args.concat(slice.apply(arguments, [0])))
}
}
}
此时,bind()
不仅可以绑定函数作用域,还可以固化任意参数,构造新函数。