手撕call和apply函数,详细解析
2023-10-28 06:32:43
前言
call()和apply()可以说是比较常用的方法了,今天就让我们来聊聊手写call和apply函数,在开始前我我们先来有关于这俩函数的一些内容。
作用与区别
call()和apply()是JavaScript中用来改变函数调用时this对象指向的函数。这两个函数的作用是将一个函数的this对象指向另一个对象,从而可以改变函数内部this的指向。
call() 的用法是:func.call(thisArg, arg1, arg2, ...)
,其中func是需要调用的函数,thisArg是要将this指向的对象,arg1、arg2、...是要传递给函数的参数。
apply() 的用法是:func.apply(thisArg, [args])
,其中func是需要调用的函数,thisArg是要将this指向的对象,args是要传递给函数的参数,args是一个数组。
call()和apply()的区别在于:
- call()接受多个参数,而apply()只接受一个参数,该参数是一个数组。
- call()中的参数是逐个传递的,而apply()中的参数是作为一个数组传递的。
实现原理
现在我们就来手撕实现call和apply函数。
// 定义call函数
Function.prototype.myCall = function (context) {
// 获取调用函数的参数
let args = [...arguments].slice(1);
// 将调用函数的this指向context
context.fn = this;
// 调用函数并返回结果
let result = context.fn(...args);
// 删除context上的fn属性
delete context.fn;
return result;
};
// 定义apply函数
Function.prototype.myApply = function (context, args) {
// 将调用函数的this指向context
context.fn = this;
// 调用函数并返回结果
let result = context.fn(...args);
// 删除context上的fn属性
delete context.fn;
return result;
};
示例
下面我们通过一个示例来看看如何使用call()和apply()函数。
// 定义一个函数
function sayName(name) {
console.log(this.name + ' ' + name);
}
// 创建一个对象
const person = {
name: '张三'
};
// 使用call()函数调用sayName函数
sayName.myCall(person, '李四'); // 张三 李四
// 使用apply()函数调用sayName函数
sayName.myApply(person, ['李四']); // 张三 李四
在上面的示例中,我们首先定义了一个名为sayName的函数,该函数接受一个参数name并输出“this.name name”。然后,我们创建了一个名为person的对象,该对象的name属性值为“张三”。接下来,我们使用call()和apply()函数调用sayName函数,并将person对象作为this对象。最后,我们在控制台中输出结果。
扩展应用
call()和apply()函数可以用来扩展和增强函数的功能。例如,我们可以使用call()和apply()函数来实现函数柯里化、函数借用等操作。
函数柯里化
函数柯里化是指将一个函数拆分成多个小函数,其中每个小函数都接受一个参数,并且返回一个新的函数。这样,我们可以通过多次调用小函数来逐步构建最终的函数。
// 定义一个函数
function sum(a, b, c) {
return a + b + c;
}
// 使用call()函数实现函数柯里化
const currySum = sum.myCall(null, 1);
const result = currySum(2)(3); // 6
在上面的示例中,我们首先定义了一个名为sum的函数,该函数接受三个参数a、b和c并返回它们的和。然后,我们使用call()函数将sum函数的this指向null,并将其第一个参数设置为1。这样,我们就得到了一个新的函数currySum,该函数接受两个参数b和c,并返回它们的和加上1。最后,我们调用currySum函数两次,分别传入参数2和3,得到最终结果6。
函数借用
函数借用是指将一个函数的属性或方法借用给另一个函数。这样,我们可以使用另一个函数来调用借用函数的属性或方法。
// 定义一个对象
const person = {
name: '张三',
sayName: function () {
console.log(this.name);
}
};
// 使用apply()函数实现函数借用
const sayName = person.sayName.myApply(null);
sayName(); // 张三
在上面的示例中,我们首先定义了一个名为person的对象,该对象的name属性值为“张三”,并有一个名为sayName的方法。然后,我们使用apply()函数将person.sayName方法的this指向null,并将其调用。这样,我们就借用了person对象的sayName方法,并将其用作一个独立的函数。最后,我们调用sayName函数,输出结果“张三”。
总结
call()和apply()函数是JavaScript中非常有用的函数,它们可以用来改变函数调用时this对象指向,从而扩展和增强函数的功能。本文对call()和apply()函数进行了详细的讲解,包括它们的用法、实现原理、示例以及扩展应用。希望读者能够通过本文对call()和apply()函数有更深入的理解,并能够熟练应用它们来优化和简化代码。