【问题标题】:What external context could cause splice to not do anything?什么外部环境会导致 splice 不做任何事情?
【发布时间】:2018-03-18 17:11:09
【问题描述】:

我有这条拼接线,两边各有一条调试线:

const obj = { x:[1,2], y:{t:"!!!"} }
const lenBefore = S.groupings.length
const ret = S.groupings.splice(gix, 0, obj)
console.log(`${lenBefore} --> ${S.groupings.length}, gix=${gix}, ret=${JSON.stringify(ret)}`)

它给出了这个输出,我认为这是不可能的:

3 --> 3, gix=2, ret=[]

splice 没有添加或删除任何内容。

另一次运行,在不同的数据上,给出了:

18 --> 18, gix=2, ret=[]

这个函数相当复杂,但我有一些单元测试来涵盖它的主要使用方式。我在运行它们时留下了console.log() 行,这些测试给了我:

1 --> 2, gix=0, ret=[]
3 --> 4, gix=1, ret=[]

即正是我所期望的。因此,实际运行时环境的某些因素导致了这种情况。

(这是一个电子应用程序,这段代码在前端部分运行,即在Chrome中有效,我正在查看控制台是Chrome开发人员工具。单元测试在mocha 3.2中运行.0,节点6.11.4。真实环境是Electron 1.8.1,也就是Chrome 59,也就是稍微新一点。)

有谁知道什么外部环境可能导致splice() 无法完成其工作?

更新:

如果我改为使用它,那么在实时代码和单元测试中一切正常:

S.groupings = S.groupings.slice(0,gix).concat(obj, S.groupings.slice(gix))

S.groupings 显然有一些东西可以阻止它发生变异,但只是在我复杂的实时代码中,而不是在单元测试中!这本身就很有趣,因为我认为不可能制作不可变的 javascript 对象...

顺便说一句,以下代码:

console.log(`S type=${typeof S}; isArray=`+ Array.isArray(S))
console.log(`S.groupings type=${typeof S.groupings}; isArray=`+ Array.isArray(S.groupings))

在实时和单元测试代码中告诉我相同的结果:

S type=object; isArray=false
S.groupings type=object; isArray=true

我也试过这个,靠近函数的顶部:

S.groupings = Array.from(S.groupings)

没有区别。 IE。所有的证据都表明S.groupings 只是一个普通的 JavaScript 数组。

更新 2:未冷冻或密封:

Object.isFrozen(S.groupings)  //false
Object.isSealed(S.groupings)  //false
Object.isExtensible(S.groupings)  //true

顺便说一句,为了缩小范围,我对真实代码进行了以下三个越来越复杂的简化,作为 mocha 测试。他们都完美地通过了。他们当然会。我决定将它包含在这里,因为它比我在上面发布的那一行提供了更多的上下文,并且还显示了一些显然 不是 解释的内容。

it("1", function(){
const S = {
  groupings:[ {a:1,b:2}, {a:2,b:"xxx"}, {a:3,b:false} ],
  tom:"hello",
  dick:[1,2,3],
  harry:null
}

const obj = {a:2.5, b:"INSERT ME"}
let gix = 2

assert.equal(S.groupings.length, 3)

S.groupings.splice(gix, 0, obj)

assert.equal(S.groupings.length, 4)

})

//--------------------------------

it("2", function(){
const S = {
  groupings:[ {a:1,b:2}, {a:2,b:"xxx"}, {a:3,b:false} ],
  tom:"hello",
  dick:[1,2,3],
  harry:null
}

const CG = [ {z:1}, {z:2}, {z:3} ]

const obj = {a:2.5, b:"INSERT ME"}

for(let gix = 0;gix < CG.length; ++gix){
  const g = CG[gix]
  if(g.z < obj.a)continue
  assert.equal(S.groupings.length, 3)
  S.groupings.splice(gix, 0, obj)
  assert.equal(S.groupings.length, 4)
  break
}
})

//--------------------------------

it("3", function(){
const data = {
  "1":{},
  "2":{
  groupings:[ {a:1,b:2}, {a:2,b:"xxx"}, {a:3,b:false} ],
  tom:"hello",
  dick:[1,2,3],
  harry:null
}}

const CG_outer = [ {z:1}, {z:2}, {z:3} ]

function inner(CG, txt){
  const S = data["2"]
  const obj = {a:2.5, b:txt}

  for(let gix = 0;gix < CG.length; ++gix){
    const g = CG[gix]
    if(g.z < obj.a)continue
    assert.equal(S.groupings.length, 3)
    S.groupings.splice(gix, 0, obj)
    assert.equal(S.groupings.length, 4)
    break
  }
}

inner(CG_outer, "INSERT ME")
assert.deepEqual(data["2"].groupings,
  [ {a:1,b:2}, {a:2,b:"xxx"}, {a:2.5, b:"INSERT ME"}, {a:3,b:false} ] )
})

【问题讨论】:

  • S.groupings = Object.freeze([…])?
  • @Bergi 猜得好——我认为这可能会导致这些症状。但我刚刚更新了我的问题以表明它没有被冻结。我确实(有点)弄清楚发生了什么,看看我的自我回答。
  • 实际上我认为冻结的对象会引发异常。它必须是一个数组,其 length 属性被覆盖不改变。

标签: javascript arrays google-chrome ecmascript-6 electron


【解决方案1】:

我终于找到了。 Electron 应用程序具有不同的后端/前端进程,以及消息解析。我正在这样做:

S = mainProcess.getLatestData(...)

如果我将其更改为:

const ret = mainProcess.getLatestData(...)
Object.assign(S, ret)

然后一切,包括splice() 都按预期工作。

不过,我无法真正解释发生了什么。 ret 未冻结、密封且可扩展。从各方面来看,它似乎都是一个普通的 JS 对象,ret.groupings 是一个简单的 JS 数组。

S 最初是来自前端的数据。 (但是,这是在事件中从前端发送的,而不是请求的,这是 Electron 中的两种不同机制。)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-04-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-26
    • 1970-01-01
    相关资源
    最近更新 更多