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

JavaScript函数作用域内声明的let变量被外部函数修改问题咨询

问题原因解答

核心本质:和let声明无关,是JavaScript引用类型的参数传递特性导致的

1. 首先明确JavaScript的两类数据存储规则

  • 基本类型(数值、字符串、布尔值、null、undefined、Symbol)存储在栈内存中,赋值、作为参数传递时,是直接拷贝完整的值,新变量和原变量完全独立,修改互不影响。
  • 引用类型(数组、对象、函数)的实际内容存储在堆内存中,栈内存只存储指向堆内存的地址。当你把引用类型作为参数传给函数时,传递的是栈内存中地址的拷贝,而不是整个堆内存内容的拷贝,这就导致函数内的形参和函数外的实参,指向的是堆内存中完全相同的对象/数组。

2. 对应你的代码场景验证

你代码里的chartData是数组,属于引用类型,当你把它传给updateDatas、labelAndCategories两个函数时,两个函数里的形参chartData1拿到的是和preparDataChart内chartData相同的堆地址:

  • labelAndCategories里调用chartData1.push(),push是数组的原地修改方法,直接修改堆内存中的原数组
  • updateDatas里调用chartData1.splice(),splice同样是原地修改数组的方法,修改的也是同一个堆内存里的数组
    所以你会感觉到“在其他函数里修改了preparDataChart内的局部变量”,这是正常的语法特性,不是变量变成了全局变量。

3. 示例复现

你可以运行这段简单代码验证特性:

function modifyArr(arrParam) {
  arrParam.push('新增内容') // 原地修改数组
}

function test() {
  let localArr = ['原有内容'] // 函数内局部变量
  modifyArr(localArr)
  console.log(localArr) // 输出 ['原有内容', '新增内容'],局部变量被修改
}
test()

4. 不想修改原数组的解决方法

如果需要避免修改原数组,传参时传入数组的拷贝即可:

  • 如果是一维数组,用浅拷贝即可:updateDatas(timeStartAndTimeEnd, [...chartData]) 或者 updateDatas(timeStartAndTimeEnd, Array.from(chartData))
  • 如果是多层嵌套的数组/对象,需要做深拷贝,比如用JSON.parse(JSON.stringify(chartData))(注意不能处理函数、Symbol等特殊类型),或者自己实现深拷贝逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.08 06:36:02