什么是apply()?
apply 是 JavaScript 中函数对象的一个方法,它和 call 方法类似,用于在特定的作用域(上下文)中调用函数。apply 方法允许你指定函数运行时的 this 值,并且可以传入一个数组作为函数的参数。
语法如下:
functionName.apply(thisArg, [argsArray])
其中:
functionName是要调用的函数名。thisArg是函数执行时的上下文对象,在函数内部通过this关键字访问。如果将thisArg设置为null或undefined,则在严格模式下this值会被设置为全局对象,非严格模式下则会被设置为window对象。argsArray是一个数组,包含了作为参数传递给函数的参数列表。
apply 方法通常用于以下几种情况:
- 将数组作为参数传递给函数。
- 在不知道参数个数的情况下,将一个数组展开成参数列表传递给函数。
下面是一个示例,演示了如何使用 apply 方法将一个数组作为参数传递给函数:
function sum(x, y) {
return x + y;
}
const numbers = [3, 4];
const result = sum.apply(null, numbers);
console.log(result); // 输出 7,等同于 sum(3, 4)
在这个示例中,apply 方法将数组 numbers 中的元素作为参数传递给 sum 函数,相当于调用了 sum(3, 4)。
与 call 方法不同的是,apply 方法接受的参数是一个数组,而 call 方法接受的是一系列参数。
为什么要使用apply()?
apply() 方法通常用于以下几种情况:
1.将数组作为参数传递给函数
当一个函数接受可变数量的参数,且这些参数已经存在于一个数组中时,可以使用 apply() 方法将数组中的元素作为参数传递给函数。这种情况下,使用 apply() 比逐个参数传递更方便、更简洁。
function sum(x, y) {
return x + y;
}
const numbers = [3, 4];
const result = sum.apply(null, numbers);
console.log(result); // 输出 7,等同于 sum(3, 4)
2.在不知道参数个数的情况下,将一个数组展开成参数列表传递给函数
有时候在编写函数时无法确定参数的数量,这时候可以将参数存储在数组中,然后使用 apply() 方法将数组展开成参数列表传递给函数。
function sum() {
let total = 0;
for (let i = 0; i < arguments.length; i++) {
total += arguments[i];
}
return total;
}
const numbers = [1, 2, 3, 4, 5];
const result = sum.apply(null, numbers);
console.log(result); // 输出 15,等同于 sum(1, 2, 3, 4, 5)
3.指定上下文对象并调用函数
apply() 方法可以用来指定函数执行时的上下文对象(即 this 值)。这种情况下,apply() 方法和 call() 方法类似。
const person = {
name: 'Alice',
greet: function() {
console.log(`Hello, my name is ${this.name}.`);
}
};
const anotherPerson = {
name: 'Bob'
};
person.greet.apply(anotherPerson);
// 输出:Hello, my name is Bob.
总的来说,apply() 方法提供了一种灵活、方便的方式来处理参数数组以及指定函数执行时的上下文,使得函数的调用更加灵活和可控。
apply()和call()的区别?
apply() 和 call() 是 JavaScript 中函数对象的两个方法,它们的作用都是在特定的作用域(上下文)中调用函数,并且可以传入参数列表。它们之间的区别主要在于传参的方式:
-
参数传递方式:
apply(thisArg, [argsArray]):apply()方法接受两个参数,第一个参数是函数执行时的上下文对象,第二个参数是一个数组,包含了作为参数传递给函数的参数列表。call(thisArg, arg1, arg2, ...):call()方法接受多个参数,第一个参数是函数执行时的上下文对象,后续参数是作为参数传递给函数的具体参数。
-
参数个数和类型:
apply()方法适用于参数数量不确定的情况,可以将一个数组作为参数传递给函数。call()方法适用于已知参数数量且类型明确的情况,可以将一系列参数作为参数传递给函数。
举例说明:
function greet(name) {
console.log(`Hello, ${name}! My name is ${this.name}.`);
}
const person = {
name: 'Alice'
};
const anotherPerson = {
name: 'Bob'
};
// 使用 apply() 方法
greet.apply(person, ['Bob']);
// 输出:Hello, Bob! My name is Alice.
// 使用 call() 方法
greet.call(anotherPerson, 'Alice');
// 输出:Hello, Alice! My name is Bob.
在这个例子中,apply() 方法将数组 ['Bob'] 作为参数传递给 greet 函数,而 call() 方法则将字符串 'Alice' 作为参数传递给 greet 函数。
如何⼿写apply()
apply 的实现跟 call 类似,只是⼊参不⼀样,apply为数组
下面是一个简单的手写实现 apply 方法的示例:
Function.prototype.myApply = function(context, argsArray) {
// 如果传入的 context 是 null 或者 undefined,则默认为全局对象(非严格模式下为 window,严格模式下为 undefined)
context = context || window;
// 将当前函数设为传入的 context 对象的方法
context.fn = this;
// 调用当前函数,并传入参数数组
const result = context.fn(...argsArray);
// 删除添加的方法
delete context.fn;
// 返回调用结果
return result;
};
// 测试
function greet(name) {
console.log(`Hello, ${name}! My name is ${this.name}.`);
}
const person = {
name: 'Alice'
};
// 使用手写的 myApply 方法调用 greet 函数
greet.myApply(person, ['Bob']);
最简化的写法
Function.prototype.apply2 = function(context, args) {
context = context || window;
let fnSymbol = Symbol()
context[fnSymbol] = this
let fn = context[fnSymbol](...args)
delete context[fnSymbol]
return fn
}
这个方法的实现步骤如下:
- 首先,判断传入的
context是否为undefined或null,如果是,则将context设置为全局对象(非严格模式下为window,严格模式下为undefined)。 - 然后,创建一个唯一的 Symbol 作为临时属性的键,以避免和对象原有的属性名冲突。
- 将当前函数设置为
context对象的临时属性。 - 调用函数,并传入参数。
- 最后,删除添加的临时属性,以避免对
context对象造成污染,并返回调用结果。
这个方法的功能与原生的 apply 方法是相似的,可以用来改变函数执行时的上下文,并传入参数列表。