Arguments 对象,call()、apply()与bind()
Arguments 对象
arguments:是一个对应于传递给函数的参数的类数组对象。arguments对象是所有(非箭头)函数中都可用的局部变量,你可以使用arguments对象在函数中引用函数的参数。此对象包含传递给函数的每个参数,第一个参数在索引0处。
ps:arguments对象不是一个 Array ,它类似于Array,但除了length属性和索引元素之外没有任何Array属性和方法。但可以被转换为一个真正的Array,方式如下:
// ES5
var args = Array.prototype.slice.call(arguments);
var args = [].slice.call(arguments);
// ES6
const args = Array.from(arguments);
const args = [...arguments];
参考资料:
1、arguments:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Functions/arguments
call()、apply()、bind()——用于改变/固定this指向
call()
call():使用一个指定的 this 值和单独给出的一个或多个参数来调用一个函数:接受的是一个参数列表
call
方法使用的指定的this
值参数应该是一个对象,如果参数为空、null
和undefined
,则默认传入全局对象。
var n = 123;
var obj = { n: 456 };
function a() {
console.log(this.n);
}
a.call() // 123
a.call(null) // 123
a.call(undefined) // 123
a.call(window) // 123
a.call(obj) // 456
call应用:调用对象的原生方法(比如对象继承的原生方法已经被覆盖,想要调用原生的方法时)
var obj = {};
obj.hasOwnProperty('toString') // false
// 覆盖掉继承的 hasOwnProperty 方法
obj.hasOwnProperty = function () {
return true;
};
obj.hasOwnProperty('toString') // true
Object.prototype.hasOwnProperty.call(obj, 'toString') // false
call巧用:将具有length属性的对象转成数组[].slice.call(arguments)
,为了提高性能,减少对原型链的追溯,一般使用Array.prototype.slice.call(arguments)
let obj1 = {
a: '我是obj1的a',
fn: function(msg) {
console.log(msg + this.a);
}
}
let obj2 = {
a: '我是obj2的a'
}
// 正常调用
obj1.fn('你说啥?') // 你说啥?我是obj1的a
// call()调用
obj1.fn.call(obj2, '你说啥?') // 你说啥?我是obj2的a
apply()
apply():使用一个指定的 this 值和单独给出的一个数组(
['eat', 'bananas']
)或数组对象(new Array('eat', 'bananas')
)参数来调用一个函数:接受的是一个包含多个参数的数组
const numbers = [5, 6, 2, 3, 7];
const max = Math.max.apply(null, numbers); // apply巧用,将数组转换为参数列表,等同于`Math.max(...numbers)`
console.log(max); // expected output: 7
const min = Math.min.apply(null, numbers);
console.log(min); // expected output: 2
apply巧用
// 应用一:找出数组的最大元素
var a = [10, 2, 4, 15, 9];
Math.max.apply(null, a) // 15
// 应用二:将数组的空元素变为undefined
Array.apply(null, ['a', ,'b'])
// [ 'a', undefined, 'b' ]
// 应用三:转换类似数组的对象
Array.prototype.slice.apply({0: 1, length: 2}) // [1, undefined]
// 应用四:绑定回调函数的对象
var o = new Object();
o.f = function () {
console.log(this === o);
}
var f = function (){
o.f.apply(o);
// 或者 o.f.call(o);
};
// jQuery 的写法
$('#button').on('click', f);
bind()
bind():使用一个指定的 this 值和单独给出的一个或多个参数来创建一个函数供后续被调用:接受的是一个参数列表
bind
每一次都会返回一个新函数,所以在事件绑定的时候不能直接在绑定参数中直接使用bind
创建匿名函数,否则会导致无法取消事件监听。
const module = {
x: 42,
getX: function() {
return this.x;
}
};
const unboundGetX = module.getX;
console.log(unboundGetX()); // The function gets invoked at the global scope
// expected output: undefined
const boundGetX = unboundGetX.bind(module);
console.log(boundGetX());
// expected output: 42
三者的区别:call
、bind
传参是参数列表,而apply
传参是数组,call
和apply
是一次性传入参数,而bind
可以分为多次传入;bind
是返回绑定this
之后的函数,便于稍后调用;call
和apply
则是立即执行。
参考资料:
1、call():https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/call
2、apply():https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/apply
3、bind():https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/bind
4、展开语法:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/Spread_syntax