Поддерживает ли 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] }
}
}
Вопросы:
Делает ли оператор спреда то же самое, что и
Object.assign()
в этом контексте и создать совершенно новый объект без риска незаконного изменения из-за сохранения ссылки наargs[type]
? Мне нужно иметь возможность полагаться на неизменное состояние объекта после его создания.Будет ли второй пример, который я показал, поддерживать живую ссылку на
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 году выкладываю)