当使用对象文字语法创建对象时,JavaScript是否维护对现有变量的引用?

时间:2017-10-27 20:43:22

标签: javascript node.js immutability spread-syntax

这是一个关于JavaScript如何添加对现有内容的引用而不是创建新内容的问题。

以下是一些有用的示例 - 在Redux reducer的上下文中,因为它是spread operatorObject.assign()的熟悉位置:

  

在这里看到我们只是返回一个带有字符串的对象文字,因此没有什么可以将参考文献拖到其他地方存在的东西。

export default (state = {}, action) => {
    switch (action.type) {
        case SOME_ACTION:
            return {
                props: 'something arbitray'
            }
    }
}

这是可疑问题:

  

我们正在返回一个对象字面值,但我们已经包含对args[type]的引用。首先,我需要肯定地知道,这是否会返回一个维护指向当前设置为args[type]的链接的对象?如果args[type]之后发生变异,是否会反映在此返回的对象中?

export default (state = {}, action) => {
    switch (action.type) {
        case SOME_ACTION:
            return {
                props: args[type]
            }
    }
}

以下是我怀疑不会出现此问题的两个例子:

  

我理解正确吗? JavaScript是否只复制属性而不保留对args[type]的任何引用?

export default (state = {}, action) => {
    switch (action.type) {
        case SOME_ACTION:
            return Object.assign({}, state, { props: args[type] })
    }
}

这是我最近学到的另一个示例,可能在语法上与Object.assign()语法完全相同:

export default (state = {}, action) => {
    switch (action.type) {
        case SOME_ACTION:
            return { ...state, props: args[type] }
    }
}

问题:

  1. 扩展运算符在此上下文中是否与Object.assign()执行完全相同的操作并创建一个全新的对象,而不会因为保留对args[type]的引用而存在非法可变性的风险?我需要能够在创建对象后依赖于对象的不可变状态。

  2. 我展示的第二个示例是否会保留对args[type]的实时引用?

  3. 我有一些代码通常会在某些内容中传播,而且我有一个省略该传播的用例,所以我很好奇这是否有问题。如何保证args[type]的随机更改不会影响此返回的对象?

    这是正确答案吗?:

    export default (state = {}, action) => {
        switch (action.type) {
            case SOME_ACTION:
                return Object.assign({}, { props: args[type] })
        }
    }
    

    [修改] 我可以通过这样做来重现这个问题:

    
    
    const arr = ['one', 'two', 'three']
    
    const args = {
      type: arr
    }
    
    const something = {
      props: args.type
    }
    
    arr.push('four') // Notice how this appears in something.props
    
    console.log(something)
    
    
    

    这就解决了这个问题(因此它似乎与原语相关而不是维护对象引用):

    
    
    const arr = ['one', 'two', 'three']
    
    const args = {
      type: arr[2]
    }
    
    const something = {
      props: args.type
    }
    
    arr[2] = 'what' // Notice how this doesn't appear in something.props
    
    console.log(something)
    
    
    

      

    更新问题

    有没有办法复制non-primitive(即:对象/数组)以便它打破此引用?

    我注意到它不适用于Object.assign()

2 个答案:

答案 0 :(得分:3)

var a = 5; var b = a;

b是否维护对?的引用?不,不是的。 您正在传递值引用/值而不是父对象。

答案 1 :(得分:0)

答案似乎是,如果值是基元,它不是问题,因为JavaScript不存储对基元的引用。

这里的解决方案是作为属性在对象或数组中传播:



const arr = ['one', 'two', 'three']

const args = {
  type: arr
}

const something = {
  props: [...args.type]
}

arr.push('four') // notice how this isn't included

console.log(something)




这很有用:Is JavaScript a pass-by-reference or pass-by-value language?

阅读浅层和深层复制也很有帮助,Hard Copy vs Shallow copy javascript

如果目标是一个对象,这就解决了这个问题:



const obj = {
  one: 'uno',
  two: 'dos',
  three: 'tres'
}

const args = {
  type: obj
}

const something = {
  props: Object.assign({}, args.type)
}

obj.four = 'four' // notice how this isn't included

console.log(something)




我记得Eric Elliot也在一本书中描述了这一点。 Object.assign()是放弃该引用的关键。 (现在在2017年,传播)