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

函数意外将数组自身作为元素嵌套,求问题原因

问题

我实现了一个根据用户选择创建N个输入字段的函数,后续需要获取这些输入值用于处理,但该函数会反复将返回的数组自身作为元素添加到数组中,形成无限嵌套的结构。只有在返回时添加conj.pop()才能解决此问题,我希望了解其原因。

控制台输出的数组示例如下:

Array(3)
0: 'A'
1: 'B'
2: (3) ['A','B','Array(3)]
展开该数组后会无限重复此结构。

测试输入为:输入2、2,然后分别输入A B、C D。

相关代码如下:

JavaScript 代码

document.getElementById("ok1").onclick = () => {

  const esp_qtd = document.getElementById("esp_qtd").value;
  const car_qtd = document.getElementById("car_qtd").value;

  document.getElementById("parte1").classList.add("invisivel");
  document.getElementById("parte2").classList.remove("invisivel");

  console.log(esp_qtd, car_qtd);

  const generateFields = (tipo) => {
    const qtd = document.getElementById(tipo + "_qtd").value;
    const parent = document.getElementById(tipo + "_lista");

    for (let i = 0; i < qtd; i++) {
      const input = document.createElement("input");
      input.setAttribute("type", "text");
      input.setAttribute("id", (tipo + i));
      parent.appendChild(input);

      if (qtd > 5) {
        if (((i + 1) % 3) == 0) parent.appendChild(document.createElement("br"));
      }

      console.log(i);
    }
  }

  generateFields("esp");
  generateFields("car");

  const inputFields = (tipo, conj) => {
    const qtd = document.getElementById(tipo + "_qtd").value;
    for (let i = 0; i < qtd; i++) {
      conj[i] = document.getElementById(tipo + i).value;
      console.log("Iteration: " + i, conj);
    }

    return conj;
  }

  document.getElementById("ok2").onclick = () => {
    const conjE = [];
    const conjC = [];

    conjE.push(inputFields("esp", conjE));
    conjC.push(inputFields("car", conjC));

    console.log(conjE);
    console.log(conjC);
  }
}

CSS 代码

* {
  font-family: 'Roboto', sans-serif;
  font-size: 14pt;
  margin-top: 1rem;
}

.invisivel {
  display: none;
}

label {
  margin-top: 1rem;
}

input {
  margin-top: 0.5rem;
  margin-right: 1rem;
  margin-bottom: 0.5rem;
}

button {
  margin-top: 1rem;
}

HTML 代码

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>DOC</title>
  <link rel="stylesheet" href="style.css">
  <link rel="preconnect" href="https://fonts.googleapis.com">
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
  <link href="https://fonts.googleapis.com/css2?family=Roboto&display=swap" rel="stylesheet">
</head>

<body>

  <div class="container">

    <!-- PART 1 -->

    <div id="parte1">
      <form>
        <label>N1</label><br>
        <input type="text" id="esp_qtd"><br>
        <label>N2</label><br>
        <input type="text" id="car_qtd"><br>
        <button id="ok1" type="button">OK</button>
      </form>
    </div>

    <!-- PART 2 -->

    <div id="parte2" class="invisivel">
      <div id="esp_lista">
        <label>ELEMENTS 1</label><br>
      </div>

      <div id="car_lista">
        <label>ELEMENTS 2</label><br>
      </div>
      <button id="ok2" type="button">OK</button>
    </div>

  </div>

  <script src="index.js"></script>
</body>

</html>

原因分析

问题核心出在这两行代码的逻辑错误:

conjE.push(inputFields("esp", conjE));
conjC.push(inputFields("car", conjC));

1. 数组的引用特性

JavaScript里数组是引用类型,你把conjE传给inputFields函数时,函数操作的是数组本身,而不是它的副本。在inputFields内部,你已经把输入值依次赋值给了conj的索引项(比如conj[0] = 'A'、conj[1] = 'B'),这时候conjE已经是['A', 'B']了。

2. push操作的叠加问题

当你调用conjE.push(inputFields("esp", conjE))时,inputFields会返回conjE本身(函数最后return conj;),这行代码等价于:

// 先执行inputFields,把conjE填充为['A','B']
inputFields("esp", conjE);
// 再把conjE自己推到自己里面
conjE.push(conjE);

这就导致conjE变成了['A', 'B', conjE],因为数组是引用类型,最后一个元素就是数组本身,展开时自然会无限嵌套。

3. 为什么conj.pop()能临时解决

你在inputFields返回前加conj.pop(),本质是把刚才push进去的数组自身给移除了,刚好修正了错误操作带来的额外元素,但这是个绕弯的临时方案。


正确的写法

根本不需要用push,因为inputFields已经直接修改了传入的数组,直接调用函数即可:

document.getElementById("ok2").onclick = () => {
  const conjE = [];
  const conjC = [];

  inputFields("esp", conjE);
  inputFields("car", conjC);

  console.log(conjE); // 输出 ['A','B']
  console.log(conjC); // 输出 ['C','D']
}

或者更合理的写法是让inputFields自己创建数组并返回,避免依赖外部传入的数组,逻辑更清晰:

const inputFields = (tipo) => {
  const qtd = document.getElementById(tipo + "_qtd").value;
  const conj = [];
  for (let i = 0; i < qtd; i++) {
    conj[i] = document.getElementById(tipo + i).value;
  }
  return conj;
}

// 调用时直接接收返回值
document.getElementById("ok2").onclick = () => {
  const conjE = inputFields("esp");
  const conjC = inputFields("car");

  console.log(conjE);
  console.log(conjC);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 23:50:32