javascript递归调用function向scope外数组push新值的时候为什么会同时改变整个数组的值?

发布于 2022-09-04 13:06:11 字数 2014 浏览 17 评论 0

我本来想用javascript写一段程序,把兼并在一起的一行数据扩展成多行数据。比如下面这一行

[["a1","a2","a3","a4","a5","a6","a7"],["b1","b2","b3","b4","b5"],["c1","c2","c3"]]

我希望输出成

[ [ 'a1', 'b1', 'c1' ],
  [ 'a1', 'b1', 'c2' ],
  [ 'a1', 'b1', 'c3' ],
  [ 'a1', 'b2', 'c1' ],
  ...
  [ 'a7', 'b5', 'c1' ],
  [ 'a7', 'b5', 'c2' ],
  [ 'a7', 'b5', 'c3' ] ]

大致写了一下程序:

function tableDecompress(t){
  // var t = [["a1","a2","a3","a4","a5","a6","a7"],["b1","b2","b3","b4","b5"],["c1","c2","c3"]]
  var xecimal = t.map(function(e,i,a){
    if(i<a.length-1){
      return xecimalCalc(a.slice(i+1))
    }else{
      return 1
    }
  })
  function xecimalCalc(arr){
    return arr.map(e=>e.length).reduce((a,b)=>a*b)
  }
  var ttlCell = xecimalCalc(t)
  var result= new Array(ttlCell)
  result.fill([])
  fillIt(t,0,[],[])
  function fillIt(arrOutter,iOutter,valueStore,addr){
    arrOutter[iOutter].forEach(function(e,i,a){
      var vStore = valueStore
      var addrS = addr
      vStore[iOutter]=e
      addrS[iOutter]=i
      if(iOutter<arrOutter.length-1){
        fillIt(arrOutter,iOutter+1,vStore,addrS)
      }else{
        addrSeq = addrS.map((e,i)=>e*xecimal[i]).reduce((a,b)=>a+b)
        result[addrSeq]=result[addrSeq].concat(vStore)
      }
    })
  }
  return result
}

这里面:

function xecimalCalc(arr){
    return arr.map(e=>e.length).reduce((a,b)=>a*b)
  }
  var ttlCell = xecimalCalc(t)
  var result= new Array(ttlCell)
  result.fill([])

是我后面改过来的,原先就只是声明一个var result=[],在fillIt这个函数里面else分支直接result.push(vStore),但是如果这样做的话呢,就会变成下面的结果:

 [ 'a7', 'b5', 'c3' ],
 [ 'a7', 'b5', 'c3' ] ,
 [ 'a7', 'b5', 'c3' ] ,
 [ 'a7', 'b5', 'c3' ] 
....
 [ 'a7', 'b5', 'c3' ] ]

在else分支里面我试过console.log(vStore),还把addrS也算出来了,觉得这样子总不会重复覆盖了吧,但是仍旧不是那么回事。只有当我事先建好一个刚好够长的数组,把这个数组用[]填充好,之后不用赋值而是用concat的时候才能正常运行。

实在是搞不懂到底为啥会这样?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

帅气尐潴 2022-09-11 13:06:11

多谢评论里的指点。所以问题是出在这两行代码:

var vStore = valueStore
var addrS = addr

对object用赋值只能是传递一个reference,要想做clone需要用下面的方法:

var vStore = valueStore.slice(0)
var addrS = addr.slice(0)

修改以后可以正常运行。

function tableDecompress(t){
  var result = []
  fillIt(t,0,[],[])
  function fillIt(arrOutter,iOutter,valueStore,addr){
    arrOutter[iOutter].forEach(function(e,i,a){
      var vStore = valueStore.slice(0)
      var addrS = addr.slice(0)
      vStore[iOutter]=e
      addrS[iOutter]=i
      if(iOutter<arrOutter.length-1){
        fillIt(arrOutter,iOutter+1,vStore,addrS)
      }else{
        result.push(vStore)
      }
    })
  }
  return result
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文