现代 JavaScript 教程:数组下标调用函数时 `this` 指向哪里?——`arr[2]()` 背后的对象方法调用机制
文档教程前端【免费下载链接】zh.javascript.info现代 JavaScript 教程The Modern JavaScript Tutorial以最新的 ECMAScript 规范为基准通过简单但足够详细的内容为你讲解从基础到高阶的 JavaScript 相关知识。项目地址https://gitcode.com/gh_mirrors/zh/zh.javascript.info点击查看免费下载数组Array是 JavaScript 中最常用的有序集合但它的本质仍然是对象arr[0]与obj[key]是同一种语法。当数组中存放的是函数并通过arr[2]()这样的下标语法调用时this究竟指向谁本文以现代 JavaScript 教程中的一道经典习题在数组上下文调用为骨架结合仓库中「数组」「对象方法与 this」「Reference Type」等章节的源码级原理彻底讲清数组元素调用函数的this绑定规则帮助你建立函数调用方式决定this的清晰认知。题目结果是什么为什么这道题出自 1-js/05-data-types/04-array/3-call-array-this/task.md重要性标记为 5importance: 5是数组章节中一道高频易错的思维题let arr [a, b]; arr.push(function() { alert( this ); }); arr[2](); // ?先别急着运行想一想arr[2]取出来的是一个函数再紧跟()调用它。此时函数内部的this是什么alert(this)会弹出什么内容标准答案this指向数组本身答案在 solution.md 中给出了非常精炼的解释arr[2]()调用从句法来看可以类比于obj[method]()与obj对应的是arr与method对应的是2。也就是说arr[2]()本质上就是从对象arr上取出名为2的属性一个函数并以对象方法的方式调用它。因此它接收this引用的对象就是arralert(this)会输出整个数组let arr [a, b]; arr.push(function() { alert( this ); }) arr[2](); // a,b,function(){...}调用后arr一共有 3 个元素最开始的两个字符串a、b再加上后来通过push添加进来的一个函数。所以this的字符串化结果就是由逗号连接的a,b,function(){...}。为什么arr[2]()等价于obj[method]()数组是特殊对象下标访问本质是属性访问要理解上面这个结论必须回到数组的本质。在 1-js/05-data-types/04-array/article.md 的「内部」一节明确写道数组是一种特殊的对象。使用方括号来访问属性arr[0]实际上是来自于对象的语法。它其实与obj[key]相同其中arr是对象而数字用作键key。也就是说arr[2]中的数字下标2对 JavaScript 引擎而言就是一个普通的属性键key。这一点在数组章节中其实早有铺垫——数组可以存储任何类型的元素包括函数// 混合值 let arr [ Apple, { name: John }, true, function() { alert(hello); } ]; // 获取索引为 3 的函数并执行 arr[3](); // hello正因为数组元素可以是函数而数组本身是对象arr[3]()与arr[2]()就完全落入了对象方法调用的范畴。this的值取决于调用方式而不是函数定义位置在 1-js/04-object-basics/04-object-methods/article.md 的「方法中的 this」一节中教程给出了最核心的规则this的值就是在点之前的这个对象即调用该方法的对象。更一般地这一章还强调了一个容易被其他语言背景开发者误解的事实JavaScript 的this是自由的它的值在调用时计算取决于点符号前/调用者上下文里的是什么对象而不是函数声明在哪里。例如let user { name: John }; let admin { name: Admin }; function sayHi() { alert( this.name ); } user.sayHi sayHi; admin.sayHi sayHi; user.sayHi(); // Johnthis user admin.sayHi(); // Adminthis admin同一个函数挂到不同对象上、以不同对象调用this就不同。回到题目arr[2]()中函数是以arr为调用者被调用的this自然就是arr。深层机制Reference Type引用类型如果你还想知道为什么arr[2]()能正确把this传给函数而let f arr[2]; f()就不行那就需要进入高阶主题 1-js/99-js-misc/04-reference-type/article.md 一探究竟。obj.method()在语法上包含两个操作点.或方括号[...]取出属性obj.method的值()立即执行它。this的信息从第一步传到第二步靠的是一个语言内部的规范类型——Reference Type。它是一个三元组合(base, name, strict)base来源对象这里就是arrname属性名这里就是数字2strict严格模式下为true。当()被作用在这个 Reference Type 上时调用会接收到完整的对象与方法信息从而把this设置为base即arr。这也是为什么只有直接以obj.method()或obj[method]()语法调用时this才被正确传递——方括号与点号在这里作用相同arr[2]()正是后者。反过来一旦把函数取出来赋给变量再调用Reference Type 会被整体丢弃只剩下裸函数this就丢失了let f arr[2]; f(); // this undefined严格模式报错或输出 undefined这恰好印证了 solution.md 的结论arr[2]()是对象方法式调用而非独立函数调用。延伸思考这道题教会我们什么1. 任何数组元素都可以变成方法。只要元素是函数通过下标调用时它就是该数组的方法this绑定到数组。这在编写以数组为上下文的小型回调、策略函数时可能造成意外惊喜——例如arr[0]()内部的this会是整个数组而非undefined或全局对象。2.alert(this)输出数组内容。数组有自己的toString实现返回以逗号分隔的元素列表见 数组章节的 toString 一节所以this即数组被alert字符串化后显示为a,b,function(){...}。3. 丢失this是常见 bug 源头。动态取出函数再调用let f obj.m; f()、回调传参、解构赋值等都会触发 Reference Type 被丢弃导致this丢失。解决方案包括bind、箭头函数或在调用点保持obj.method()语法——这与题目形成完美对照同样是数组里的函数直接arr[2]()与先赋值再调用结果截然不同。小结数组是特殊对象arr[i]本质是obj[key]形式的属性访问数组可存储函数arr[i]()等价于以数组为调用者的方法调用this指向数组本身本题中alert(this)输出a,b,function(){...}因为数组被字符串化为逗号分隔的元素列表深层原因是 Reference Type 机制只有obj.method()/obj[method]()直接调用才保留this绑定拆开赋值即丢失。如果希望进一步吃透相关原理建议按顺序阅读仓库中的 数组完整章节、对象方法与 this 以及高阶主题 Reference Type并结合本题的 task.md 与 solution.md 亲手运行验证。赞分享文档教程前端【免费下载链接】zh.javascript.info现代 JavaScript 教程The Modern JavaScript Tutorial以最新的 ECMAScript 规范为基准通过简单但足够详细的内容为你讲解从基础到高阶的 JavaScript 相关知识。项目地址https://gitcode.com/gh_mirrors/zh/zh.javascript.info点击查看免费下载相关推荐JavaScript 数组上下文中的方法调用深入剖析 arr[2]() 的 this 绑定JavaScript 数组上下文中的方法调用深入剖析 arr 2 的 this 绑定 在 JavaScript 中数组可以存放任意类型的元素——包括函数。当文档/教程前端基于 replexica 的开源本地化工程工具链从 Lingo CLI 到 React 编译器的 i18n 实战指南基于 replexica 的开源本地化工程工具链从 Lingo CLI 到 React 编译器的 i18n 实战指南 replexica 是 Lingo.de文档教程前端Modern JavaScript Tutorial 精读数组上下文中的方法调用 arr[2]() 与 this 绑定原理Modern JavaScript Tutorial 精读数组上下文中的方法调用 arr 2 与 this 绑定原理 本篇技术文章围绕现代 JavaScrip文档/教程前端上一篇技术方案使用ONNX模型实现高效图像标签生成系统下一篇ACE-Step UI终极指南免费开源AI音乐生成工具完整使用教程创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考