JavaScript函数Call、Apply原理实例解析
什么是Call、Apply
在JavaScript中,每个函数都是一个对象,函数对象可以有方法,比如call和apply方法。这两个方法都是用来改变函数内部this的指向的。
call方法的语法如下:
function.call(thisArg, arg1, arg2, ...)
- thisArg:在调用函数时,将其绑定到函数的this上。
- arg1,arg2,...:传递给函数的参数列表。
apply方法的语法如下:
function.apply(thisArg, [argsArray])
- thisArg:在调用函数时,将其绑定到函数的this上。
- argsArray:传递给函数的参数列表,必须是数组或类数组对象。
Call、Apply的作用
改变this指向
通过call和apply方法,可以改变函数内部this的指向,让其指向指定的对象。下面给出一个简单的例子:
var obj = {
name: 'Tom'
};
function sayName() {
console.log(this.name);
}
sayName(); // undefined
sayName.call(obj); // Tom
在上面的例子中,sayName函数本身并没有任何问题,但是在全局上下文,this指向的是全局对象,因此打印出undefined。在使用call方法时,指定this为obj,因此打印出了obj的name属性。
借用函数对象
通过call和apply方法,可以实现函数对象的借用。下面给出一个示例:
function sum() {
var result = 0;
for(var i = 0; i < arguments.length; i++) {
result += arguments[i];
}
return result;
}
var arr = [1, 2, 3];
console.log(sum.apply(null, arr)); // 6
在上面的例子中,sum函数实现了一个可以接收任意数量参数的求和函数。在调用时,我们将数组arr作为apply方法的第二个参数传入,因此实现了对数组的求和。
Call、Apply的实现原理
在JavaScript中,每个函数都是Function类型,因此每个函数对象都具有call和apply方法。可以通过以下方式来自己实现一个call方法:
Function.prototype.myCall = function(thisArg, ...args) {
// 1. 判断this的类型,必须为函数类型
if(typeof this !== 'function') {
throw new TypeError('myCall should be call on a function!');
}
// 2. 将this关键字绑定到thisArg上
thisArg = thisArg || window;
thisArg.fn = this;
// 3. 执行函数
var result = thisArg.fn(...args);
// 4. 删除函数属性
delete thisArg.fn;
// 5. 返回函数执行结果
return result;
}
实现apply方法的原理与call方法类似,只是参数列表不同。
Function.prototype.myApply = function(thisArg, args) {
// 1. 判断this的类型,必须为函数类型
if(typeof this !== 'function') {
throw new TypeError('myApply should be apply on a function!');
}
// 2. 将this关键字绑定到thisArg上
thisArg = thisArg || window;
thisArg.fn = this;
// 3. 执行函数
var result = thisArg.fn(...args);
// 4. 删除函数属性
delete thisArg.fn;
// 5. 返回函数执行结果
return result;
}
示例
示例一
var obj1 = {
name: 'Tom',
age: 18,
sayNameAge: function() {
console.log(this.name + ' is ' + this.age + ' years old.');
}
};
var obj2 = {
name: 'Jerry',
age: 20
};
obj1.sayNameAge(); // Tom is 18 years old.
obj1.sayNameAge.call(obj2); // Jerry is 20 years old.
在上面的例子中,obj1和obj2都有name和age属性,但是obj1有一个sayNameAge方法,该方法打印出名字和年龄。在调用sayNameAge方法时,this指向的是obj1,因此第一次调用打印出了Tom的信息。在使用call方法调用sayNameAge方法时,this指向的是obj2,因此第二次调用打印出了Jerry的信息。
示例二
function max() {
var result = -Infinity;
for(var i = 0; i < arguments.length; i++) {
if(arguments[i] > result) {
result = arguments[i];
}
}
return result;
}
var arr1 = [1, 2, 3];
var arr2 = [4, 5, 6];
console.log(max.apply(null, arr1)); // 3
console.log(max.call(null, ...arr2)); // 6
在上面的例子中,max函数是一个求最大值的函数。在第一个例子中,我们使用apply方法将数组arr1作为参数列表传入函数,从而实现了对数组的求最大值。在第二个例子中,我们使用call方法时,使用spread操作符将数组arr2展开成参数列表,并按原样调用函数,也实现了对数组的求最大值。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:JavaScript函数Call、Apply原理实例解析 - Python技术站