我写了以下JavaScript:
var myArray = ['a', 'b', 'c'];
var copyOfMyArray = myArray;
copyOfMyArray.splice(0, 1);
alert(myArray); // alerts ['b','c']
alert(copyOfMyArray); // alerts ['b','c']
var myNumber = 5;
var copyOfMyNumber = myNumber;
copyOfMyNumber = copyOfMyNumber - 1;
alert(myNumber); // alerts 5
alert(copyOfMyNumber); // alerts 4
Run Code Online (Sandbox Code Playgroud)
此代码声明一个变量myArray并将其设置为数组值.然后它声明第二个变量copyOfMyArray并将其设置为myArray.它执行操作copyOfMyArray,然后警告两者myArray和copyOfMyArray.不知何故,当我执行操作时copyOfMyArray,似乎执行相同的操作myArray.
然后代码使用数字值执行相同的操作:它声明一个变量myNumber并将其设置为数字值.然后它声明第二个变量copyOfMyNumber并将其设置为myNumber.它执行操作copyOfMyNumber,然后警告两者myNumber和copyOfMyNumber.在这里,我得到预期的行为:对不同的价值观myNumber和copyOfMyNumber.
数组和JavaScript中的数字有什么区别,它似乎更改数组会更改数组副本的值,而更改数字不会更改数字副本的值?
我猜测由于某种原因,数组是通过引用引用的,而数字是按值引用的,但为什么呢?我如何知道其他对象的行为?
Fel*_*ing 95
JavaScript中的数组也是一个对象,变量只包含对象的引用,而不是对象本身.因此,两个变量都引用同一个对象.
您与数字示例的比较不正确顺便说一句.您为其分配了一个新值copyOfMyNumber.如果为其分配新值copyOfMyArray也不会更改myArray.
您可以使用slice [docs]创建数组的副本:
var copyOfMyArray = myArray.slice(0);
Run Code Online (Sandbox Code Playgroud)
但请注意,这只会返回一个浅表副本,即不会克隆数组中的对象.
Poi*_*nty 20
嗯,唯一可能的答案 - 也就是正确答案 - 是你实际上并没有复制数组.当你写作
var copyOfArray = array;
Run Code Online (Sandbox Code Playgroud)
您将同一数组的引用分配给另一个变量.换句话说,他们都指向同一个物体.
Sal*_*ore 12
所以这里的每个人都做了很好的解释为什么会这样 - 我只想放弃一条线让你知道我是如何解决这个问题的 - 非常容易:
thingArray = ['first_thing', 'second_thing', 'third_thing']
function removeFirstThingAndPreserveArray(){
var copyOfThingArray = [...thingArray]
copyOfThingArray.shift();
return copyOfThingArray;
}
Run Code Online (Sandbox Code Playgroud)
这是使用... spread语法.
编辑:至于为什么这样,并回答你的问题:
数组和JavaScript中的数字有什么区别,它似乎更改数组会更改数组副本的值,而更改数字不会更改数字副本的值?
答案是在JavaScript中,数组和对象是可变的,而字符串和数字以及其他基元是不可变的.当我们做一个如下任务:
var myArray = ['a', 'b', 'c']; var copyOfMyArray = myArray;
copyOfMyArray实际上只是对myArray的引用,而不是实际的副本.
我会推荐这篇文章,什么是不可变和可变数据结构?,深入挖掘这一主题.
我发现这是对对象或数组进行深度克隆的最简单方法:
const objectThatIWantToClone = { foo: 'bar'};
const clone = JSON.parse(JSON.stringify(objectThatIWantToClone));
Run Code Online (Sandbox Code Playgroud)
通过对其进行字符串化,我们将其复制为不可变的,然后可以将其转换回JSON。
https://codepen.io/Buts/pen/zWdVyv
克隆对象 -
A loop / array.push产生与array.slice(0)或相似的结果array.clone().值都是通过引用传递的,但由于大多数原始数据类型都是不可变的,因此后续操作会产生所需的结果 - "克隆".当然,对象和数组不是这样,它允许修改原始引用(它们是可变类型).
请看以下示例:
const originalArray = [1, 'a', false, {foor: 'bar'}]
const newArray = [];
originalArray.forEach((v, i) => {
newArray.push(originalArray[i]);
});
newArray[0] = newArray[0] + 1;
newArray[1] = 'b';
newArray[2] = true;
newArray[3] = Object.assign(newArray[3], {bar: 'foo'});
Run Code Online (Sandbox Code Playgroud)
在newArray索引上运行的操作都会产生所需的结果,但final(object)除外,因为它是通过引用复制的,它也会改变originalArray [3].
https://jsfiddle.net/7ajz2m6w/
请注意,array.slice(0) and array.clone()这也受到同样的限制.
解决此问题的一种方法是在推送序列期间有效地克隆对象:
originalArray.forEach((v, i) => {
const val = (typeof v === 'object') ? Object.assign({}, v) : v;
newArray.push(val);
});
Run Code Online (Sandbox Code Playgroud)
https://jsfiddle.net/e5hmnjp0/
干杯
浅复制的问题是,所有对象都不会被克隆,而是会获得引用。因此 array.slice(0) 仅适用于文字数组,但它不会对对象数组进行浅复制。在这种情况下,一种方法是..
var firstArray = [{name: 'foo', id: 121}, {name: 'zoo', id: 321}];
var clonedArray = firstArray.map((_arrayElement) => Object.assign({}, _arrayElement));
console.log(clonedArray);
// [{name: 'foo', id: 121}, {name: 'zoo', id: 321}] // shallow copy
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
45552 次 |
| 最近记录: |