Поддерживает ли JavaScript ссылку на существующие переменные, когда объекты создаются с использованием литерального синтаксиса объекта?

Это вопрос о том, как JavaScript может добавить ссылку на существующую, а не создавать новую.

Вот некоторые примеры, которые, надеюсь, достаточно иллюстративны, в контексте редуктора Redux, потому что это знакомое место для spread operator или же 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()

2 ответа

Решение

var a = 5; var b = a;

Сохраняет ли b ссылку на a? Нет. Вы передаете ссылку на значение / значение, а не родительский объект.

Кажется, ответ таков: проблема не в том, что значение является примитивным, потому что 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 языком передачи по ссылке или передачей по значению?

Чтение о мелком и глубоком копировании также полезно, печатная копия и мелкая копия 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)

Я помню, что это описано в книге Эрика Эллиота также. Object.assign() является ключом для отказа от этой ссылки. (и сейчас в 2017 году выкладываю)

Другие вопросы по тегам