2

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

在 Redux reducer 的上下文中,这里有一些示例希望足以说明问题,因为它是spread operatoror的熟悉位置Object.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]吗?

我有一些通常会在某些东西中传播的代码,并且我有一个省略了传播的用例,所以我很好奇这是否会成为问题。我如何保证随机更改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()

4

2 回答 2

3

var a = 5; var b = a;

b 是否保持对 a 的引用?不,不是的。您传递的是值引用/值,而不是父对象。

于 2017-10-27T20:49:15.117 回答
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)

这很有帮助:JavaScript 是按引用传递还是按值传递语言?

阅读浅拷贝和深拷贝也很有帮助,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 年,传播)

于 2017-10-27T22:45:26.710 回答