本文详细解析JavaScript中apply、call和bind三种函数调用方式。通过对比代码示例,阐明三者如何指定this指针及参数传递的差异:call和apply立即执行但参数格式不同,bind返回新函数。掌握这些特性有助于更灵活地控制函数上下文。
JavaScript函数调用机制
函数调用机制
在深入探讨JavaScript中的apply、call和bind之前,首先需要明确JavaScript中函数调用的基本方式有哪些。
作为普通函数调用
作为对象方法调用
作为构造函数调用
通过call()和apply()方法进行间接调用
前三种调用方式属于基础概念,此处不再赘述,重点在于第四种间接调用方式。
接下来重点解析第四种调用方式。
利用call()和apply()进行间接调用
实际上,可以将这两个方法视为对象的方法,通过调用该方法来间接执行目标函数。
function f(){}
f.call(o);
f.apply(o);
call()和apply()的第一个参数指定了函数执行时的上下文对象(即this指向),在函数内部可以通过this访问该上下文。
那么,call和apply有何异同?bind又扮演什么角色?下文将详细解析三者的区别与联系。
call()方法详解
call()方法详解
call()方法允许为函数指定特定的this指针(此处沿用习惯说法,暂不纠结术语严谨性)以及具体的参数。例如存在如下函数定义:
var fn = function (arg1, arg2) {
console.log(this, arg1, arg2);
}
尝试调用该函数:
fn.call(null, 'Skylor', 'min'); //1
fn.call(undefined, 'Skylor', 'min'); //2
var fx = function() {}
fn.call(fx, 'Skylor', 'min'); //3
上述三种call调用的返回值分别是什么?直接查看结果:
1. null "Skylor" "min"
2. undefined "Skylor" "min"
3. fx "Skylor" "min"
实际在浏览器控制台中运行会发现,结果与预期略有不同(注:浏览器环境中this默认指向window对象):
chrome
1. Window "Skylor" "min"
2. Window "Skylor" "min"
3. fx "Skylor" "min"
尽管存在环境差异,但这已充分展示了call方法的核心行为。
注意,call方法的第一个参数用于指定this指针,后续每个参数依次对应函数的具体参数。这意味着调用者必须显式地逐个传入参数。
apply()方法详解
apply()方法详解
apply()可视为call()的兄弟方法,两者功能相似,仅在参数传递形式上存在差异。示例如下:
fn.apply(null, ['Skylor', 'min']); //1
fn.apply(fx, ['Skylor', 'min']); //2
注意,apply方法的第二个参数是一个数组,用于包含所有需要传递给目标函数的参数,这是它与call的主要区别。
bind()方法详解
bind()方法详解
bind()虽然常与apply、call并列讨论,但它并非直接调用函数,而是返回一个新的函数。
bind()允许指定this指针,但它不会立即执行原函数,而是返回一个绑定了特定this和参数的新函数。示例如下:
var fnbound = fn.bind(null, 'Skylor', 'min');
此时,fnbound是一个新函数,其this指向null,且预置了参数['Skylor', 'min']。调用该新函数:
执行fnbound();
输出结果:
null, 'Skylor', 'min'
此处忽略浏览器环境对this的默认处理差异。
bind与其他两者的核心区别在于:它不直接调用函数,而是返回一个绑定了特定this和参数(参数传递方式同call,需逐个指定)的新函数。
最后提供一个综合示例:
var shoppingCart = (function(){
var _calculatePrice = function () {
return this.price * this.amount;
};
return {
calculatePrice : _calculatePrice
}
})();
var goods = {
name : ‘hammer',
price: 199,
amount : 2
};
shoppingCart.calculatePrice.call(goods);
本文到此结束。
以上为JavaScript中apply、call和bind的完整解析,希望能帮助读者理解。如有疑问欢迎留言,我们将及时回复。感谢支持。