JavaScript 中 call 和 apply 的常见错误及如何避免

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

JavaScript 中 call 和 apply:常见错误及如何避免



你是否曾经看过别人的 JavaScript 代码,看到类似 func.call(this, arg1, arg2) 或 func.apply(this, [arg1, arg2]) 这样奇怪的构造?并问自己:“它们之间到底有什么区别?”如果是这样,你并不孤单。“call 和 apply 有什么区别?” 这个问题是 Stack Overflow 上最热门的问题之一,拥有数十万次浏览量。这并非偶然。



混淆 call 和 apply 是新手(甚至不仅仅是新手)的经典陷阱。在本文中,我们不仅会讲解理论。我们还将分析 5 个真实错误,展示如何修复它们,并提供一个清晰的算法,让你永远摆脱混淆。开始吧!



快速入门:什么是 call 和 apply?



在深入探讨错误之前,让我们先回顾一下基础知识。call 和 apply 方法是 JavaScript 中函数的内置方法。它们的主要任务是显式指定函数的调用上下文 (this)。换句话说,它们允许你说:“嘿,函数,假装你正在这个对象上工作”。



语法:



func.call(context, arg1, arg2, ...);func.apply(context, [arg1, arg2, ...]);


关键区别:

  • call 接受参数以逗号分隔(列表)。
  • apply 接受参数以数组形式(或类数组对象)。


仅此而已。这是唯一的区别。但正是这个“小细节”导致了大多数错误。让我们来分析一下。



使用 call 和 apply 时的 5 大错误



错误 #1:混淆参数列表(最常见!)



这是所有错误中的“王者”。你编写了一个期望逐个接收参数的函数,却通过 call 传递了一个数组。或者反过来。



灾难示例:



function greet(greeting, punctuation) {    console.log(greeting + ', ' + this.name + punctuation);}

const user = { name: '安娜' };

// 错误:传递数组,但使用了 callgreet.call(user, ['你好', '!']); // 输出:"你好,! 安娜,undefined" — 完全错误!


为什么会这样? call 期望逐个接收参数。它只接收了一个参数——整个数组——并将其放入变量 greeting 中。punctuation 变成了 undefined。



如何修复? 如果数据已经在数组中,请使用 apply:



greet.apply(user, ['你好', '!']); // 输出:"你好, 安娜!" — 正确!


或者使用展开运算符(现代方法)展开数组:



greet.call(user, ...['你好', '!']); // 也能工作!


错误 #2:忘记 apply 可以处理类数组对象



许多人认为 apply 只接受真正的数组。实际上,它接受任何类数组对象:它必须具有 length 属性和数字键。



示例:



function sum() {    let total = 0;    for (let i = 0; i < arguments.length; i++) {        total += arguments[i];    }    return total;}

// 传递的不是数组,而是带有 length 的对象const args = { 0: 5, 1: 10, 2: 15, length: 3 };

console.log(sum.apply(null, args)); // 输出:30 — 有效!


但要小心:如果对象没有 length,apply 会直接忽略它。这是处理 arguments(已过时的对象)或 NodeList 时的常见错误。



错误 #3:在只需简单调用的地方使用 call/apply



有时新手会过度使用

博客

书籍推荐