You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JavaScript Array.push非原始值变量使用问题及闭包函数数组变量疑问

关于JavaScript数组push和闭包的两个问题解答

问题1:为啥推入非原始值时,Array.push的表现和原始值不一样?

其实你可能有点误解啦——Array.push()不管推原始值还是引用类型,都是可以用变量的!两者的差异完全是JavaScript对不同类型的存储机制导致的:

  • 对于原始值(比如数字、字符串、布尔值这些),它们是直接存在栈内存里的。当你把变量push进数组时,数组里存的是这个值的拷贝版。之后你再修改原变量,数组里的内容不会跟着变,比如:
let num = 10;
let arr = [];
arr.push(num);
num = 20;
console.log(arr[0]); // 还是10,和原变量没关系了
  • 而引用类型(比如对象、数组、函数)是存到堆内存里的,变量本身只是个“指向堆内存的地址”。当你push这个变量时,数组里存的是这个地址的拷贝,和原变量指向同一个堆内存里的对象。所以之后你修改原变量指向的对象内容,数组里的元素自然也会跟着变,比如:
let obj = {name: "小明"};
let arr = [];
arr.push(obj);
obj.name = "小红";
console.log(arr[0].name); // 变成小红了,因为俩变量指向同一个对象

你觉得“push好像没使用变量”,其实是引用类型的共享特性搞的鬼,本质上push确实用了变量哦~

问题2:闭包函数里,为啥数组里的函数都引用同一个i?

先看你给的这段经典代码:

function buildFunctions() { var arr = []; for (var i = 0; i < 3; i++) { arr.push(function() { console.log(i) }) } return arr; }
var fs = buildFunctions();
fs[0](); // 3
fs[1](); // 3
fs[2](); // 3

核心原因有两个:

  1. var没有块级作用域:用var声明的i是属于buildFunctions整个函数作用域的,整个for循环里只有这一个i变量——每次循环只是更新它的值,不是创建新的i。
  2. 闭包捕获的是变量引用,不是当时的值:你push进数组的那些匿名函数并没有立即执行,它们只是“记住”了自己所在的作用域链,也就是捕获了对这个唯一的i的引用。

等你之后调用fs[0]()这些函数时,for循环早就跑完了,i的值已经变成3了,所以所有函数打印的都是这个最终的3。

如果想让每个函数打印对应的0、1、2,有两个简单办法:

  • 改用let声明i:let有块级作用域,每次循环都会创建一个新的i变量,每个函数捕获的是当前循环的那个独立的i:
function buildFunctions() {
  var arr = [];
  for (let i = 0; i < 3; i++) {
    arr.push(function() { console.log(i) })
  }
  return arr;
}
var fs = buildFunctions();
fs[0](); // 0
fs[1](); // 1
fs[2](); // 2
  • 用立即执行函数(IIFE)创建独立作用域:把当前的i传进去当参数,每个IIFE里的参数都是独立的,函数捕获的是这个参数:
function buildFunctions() {
  var arr = [];
  for (var i = 0; i < 3; i++) {
    arr.push((function(num) {
      return function() { console.log(num) }
    })(i))
  }
  return arr;
}
var fs = buildFunctions();
fs[0](); // 0
fs[1](); // 1
fs[2](); // 2

内容的提问来源于stack exchange,提问作者Fatah

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 11:09:44