我做了"x=y",改了"x"之后,它也改了"y"。我该如何防止这种情况?
After I do "x=y" and change "x", it also changes "y". How do I prevent this?
例如我有 listings
数组:
[ { name: 'bob', price: '10' }, { name: 'jack', price: '12' } ]
我正在尝试找到最低价的卖家并稍后使用它的数据。
我做 var currentLowestSeller = listings[0];
现在 currentLowestSeller
是:
{ name: 'bob', price: '10' }
稍后我做的更改是 currentLowestSeller
但我不想更改主 listings
数组。
我做 currentLowestSeller.price = currentLowestSeller.price * 0.5;
并且在此列表数组之后如下所示:
[ { name: 'bob', price: 5 }, { name: 'jack', price: '12' } ]
如何防止这种情况发生?
如果你想重新创建这个 运行 这个代码:
var listings = [];
var name1 = 'bob';
var name2 = 'jack';
var price1 = '10';
var price2 = '12';
listings.push({
name: name1,
price: price1
})
listings.push({
name: name2,
price: price2
})
var currentLowestSeller = listings[0];
currentLowestSeller.price = currentLowestSeller.price * 0.5;
console.log(listings);
我试过的:
我尝试在执行任何操作之前创建 listings
数组的副本。
var unchangedListings = listings;
var currentLowestSeller = listings[0];
currentLowestSeller.price = currentLowestSeller.price * 0.5;
console.log(unchangedListings);
但是没有用。
后来我决定 const unchangedListings = listings;
会有帮助。但出于某种原因,它还会更改定义为常量的值。
var unchangedListings = listings;
这意味着,unchangedListings
指示 listings
的值,因此如果您更改 unchangedListings
值,则意味着您也在更新 listings
.
为防止这种情况,您需要克隆该值。您应该深度克隆该对象。
var currentLowestSeller = JSON.parse(JSON.stringify(listings[0]))
或
var currentLowestSeller = Object.assign({}, listings[0])
如果列表或字典是嵌套的,您可以使用 Ramda library:
中的 clone
import { clone } from 'ramda';
var currentLowestSeller = clone(listings[0]);
您可以在这里找到更多信息:https://medium.com/javascript-in-plain-english/how-to-deep-copy-objects-and-arrays-in-javascript-7c911359b089,它们很好地解释了浅拷贝和深拷贝之间的区别。
问题的根源
您看到的行为对大多数语言来说都是常见的,与 javascript 无关。
数组仅包含 对它们包含的对象的引用。从数组(或与此相关的对象)中提取键不会复制键的值。如果是这种情况,将无法对程序的状态进行任何更改。
var a = { toto: 1 }; // create object
var b = a; // b is pointing the the same object
b['toto'] = 2; // update the object (there is only one)
console.log(a == b); // true because a and b are the SAME object (not just equal,
// both a and b point to the same place in the computer memory)
console.log(a); // { toto: 2 } both objects have been edited
如果您需要操作一个对象,而不修改原始对象,您需要显式制作一个副本。
但是,当使用嵌套对象或嵌套数组时,就会出现问题。您需要“深拷贝”还是“浅拷贝”?
浅拷贝
浅拷贝意味着只复制“第一层”。
var a = { toto: 1, tata: { tutu: 1 } };
var b = { ... a }; // make a "shallow copy"
// We change "b", did "a" change? => No
b.toto = 2;
console.log(a); // { toto: 1, tata: { tutu: 1 } }
// "a" was not modified!
console.log(b); // { toto: 2, tata: { tutu: 1 } }
// "b" was modified!
// we change a nested object in "b", did "a" change? => Yes
b.tata.tutu = 2;
console.log(a); // { toto: 1, tata: { tutu: 2 } }
// "a" was modified!
console.log(b); // { toto: 2, tata: { tutu: 2 } }
// "b" was modified!
深拷贝
深拷贝会复制所有嵌套的数组和对象(并且会带来显着的性能成本)。
Javascript 没有内置语言来执行深拷贝,因为它不是常见的操作,而且很昂贵。
执行对象深度复制的最常见方法是使用 JSON 内置函数,但是存在许多不同优缺点的方法(例如,使用 JSON 内置函数是很快,但如果您的对象包含 NaN
或 Date
个实例,则会中断。
查看此线程以获取更多信息:What is the most efficient way to deep clone an object in JavaScript?
var a = { toto: 1, tata: { tutu: 1 } };
var b = JSON.parse(JSON.stringify(a)); // make a "deep copy"
// a and b are now completely different, they share nothing in memory
// we can edit any subobject, they will not be any consequence between them.
a.tata.tutu = 2;
Javascript(以及许多其他语言)最重要的概念之一是引用类型的概念。 Javascript 有 3 种通过引用传递的数据类型:Array
、Function
和 Object
。由于理解这一点非常重要,因此我建议阅读此 article.
你的情况:
var unchangedListings = listings; // still points to listings
var currentLowestSeller = listings[0]; // changes listings
在改变数组之前复制数组始终是一个好习惯:
const currentLowestSeller = [... listings]; // currentLowestSeller points to a new array
例如我有 listings
数组:
[ { name: 'bob', price: '10' }, { name: 'jack', price: '12' } ]
我正在尝试找到最低价的卖家并稍后使用它的数据。
我做 var currentLowestSeller = listings[0];
现在 currentLowestSeller
是:
{ name: 'bob', price: '10' }
稍后我做的更改是 currentLowestSeller
但我不想更改主 listings
数组。
我做 currentLowestSeller.price = currentLowestSeller.price * 0.5;
并且在此列表数组之后如下所示:
[ { name: 'bob', price: 5 }, { name: 'jack', price: '12' } ]
如何防止这种情况发生?
如果你想重新创建这个 运行 这个代码:
var listings = [];
var name1 = 'bob';
var name2 = 'jack';
var price1 = '10';
var price2 = '12';
listings.push({
name: name1,
price: price1
})
listings.push({
name: name2,
price: price2
})
var currentLowestSeller = listings[0];
currentLowestSeller.price = currentLowestSeller.price * 0.5;
console.log(listings);
我试过的:
我尝试在执行任何操作之前创建 listings
数组的副本。
var unchangedListings = listings;
var currentLowestSeller = listings[0];
currentLowestSeller.price = currentLowestSeller.price * 0.5;
console.log(unchangedListings);
但是没有用。
后来我决定 const unchangedListings = listings;
会有帮助。但出于某种原因,它还会更改定义为常量的值。
var unchangedListings = listings;
这意味着,unchangedListings
指示 listings
的值,因此如果您更改 unchangedListings
值,则意味着您也在更新 listings
.
为防止这种情况,您需要克隆该值。您应该深度克隆该对象。
var currentLowestSeller = JSON.parse(JSON.stringify(listings[0]))
或
var currentLowestSeller = Object.assign({}, listings[0])
如果列表或字典是嵌套的,您可以使用 Ramda library:
中的clone
import { clone } from 'ramda';
var currentLowestSeller = clone(listings[0]);
您可以在这里找到更多信息:https://medium.com/javascript-in-plain-english/how-to-deep-copy-objects-and-arrays-in-javascript-7c911359b089,它们很好地解释了浅拷贝和深拷贝之间的区别。
问题的根源
您看到的行为对大多数语言来说都是常见的,与 javascript 无关。
数组仅包含 对它们包含的对象的引用。从数组(或与此相关的对象)中提取键不会复制键的值。如果是这种情况,将无法对程序的状态进行任何更改。
var a = { toto: 1 }; // create object
var b = a; // b is pointing the the same object
b['toto'] = 2; // update the object (there is only one)
console.log(a == b); // true because a and b are the SAME object (not just equal,
// both a and b point to the same place in the computer memory)
console.log(a); // { toto: 2 } both objects have been edited
如果您需要操作一个对象,而不修改原始对象,您需要显式制作一个副本。
但是,当使用嵌套对象或嵌套数组时,就会出现问题。您需要“深拷贝”还是“浅拷贝”?
浅拷贝
浅拷贝意味着只复制“第一层”。
var a = { toto: 1, tata: { tutu: 1 } };
var b = { ... a }; // make a "shallow copy"
// We change "b", did "a" change? => No
b.toto = 2;
console.log(a); // { toto: 1, tata: { tutu: 1 } }
// "a" was not modified!
console.log(b); // { toto: 2, tata: { tutu: 1 } }
// "b" was modified!
// we change a nested object in "b", did "a" change? => Yes
b.tata.tutu = 2;
console.log(a); // { toto: 1, tata: { tutu: 2 } }
// "a" was modified!
console.log(b); // { toto: 2, tata: { tutu: 2 } }
// "b" was modified!
深拷贝
深拷贝会复制所有嵌套的数组和对象(并且会带来显着的性能成本)。
Javascript 没有内置语言来执行深拷贝,因为它不是常见的操作,而且很昂贵。
执行对象深度复制的最常见方法是使用 JSON 内置函数,但是存在许多不同优缺点的方法(例如,使用 JSON 内置函数是很快,但如果您的对象包含 NaN
或 Date
个实例,则会中断。
查看此线程以获取更多信息:What is the most efficient way to deep clone an object in JavaScript?
var a = { toto: 1, tata: { tutu: 1 } };
var b = JSON.parse(JSON.stringify(a)); // make a "deep copy"
// a and b are now completely different, they share nothing in memory
// we can edit any subobject, they will not be any consequence between them.
a.tata.tutu = 2;
Javascript(以及许多其他语言)最重要的概念之一是引用类型的概念。 Javascript 有 3 种通过引用传递的数据类型:Array
、Function
和 Object
。由于理解这一点非常重要,因此我建议阅读此 article.
你的情况:
var unchangedListings = listings; // still points to listings
var currentLowestSeller = listings[0]; // changes listings
在改变数组之前复制数组始终是一个好习惯:
const currentLowestSeller = [... listings]; // currentLowestSeller points to a new array