Почему их данные кажутся синхронными?

В javascript, когда я

var buffer = new Array();
buffer = AnotherArray;

но странно, что то, что я сделал для буферизации, оказалось, что это происходит и с AnotheArray. Например, я удалил некоторые элементы в буфере, и я обнаружил, что они также удалены в AnotherArray. Почему это и как я могу это решить?

5 ответов

Ваш код, как указано, абсолютно не приводит к тому, что массив, созданный new Array() в первой строке, и AnotherArray на следующей строке будет связан каким-либо образом. Если вы видите какой-то эффект между ними, это код, который вы не цитировали.

В частности, ваш код создает массив, а затем полностью отбрасывает его, имея buffer ссылающийся на другую вещь (которая, по имени, кажется, что это может быть массив). Но массив, созданный в первой строке, теряется.

Я подозреваю, что вы можете сделать что-то вроде этого:

var buffer = new Array();
var foo = new Array();
buffer = foo;
buffer.push("Testing");
alert(foo.length); // alerts "1", not "0"

В этом случае массив, созданный на первой строке, полностью отбрасывается, и (в третьей строке) вы указываете как buffer и foo в том же массиве. Там только один массив, но у вас есть две ссылки на него. Итак, все, что вы делаете, используя ссылку на buffer для массива, вы также видите, когда вы смотрите на тот же массив через ссылку foo. Там только один массив, у вас есть только две ссылки на него.

Если вы хотите скопировать массив, см. (Длинный путь) ниже под разделительной линией.

Если вы думаете об этом, это точно так же, как то, что происходит, когда вы передаете ссылку в функцию:

var f = new Array(); // Or better, you could use '[]' rather than 'new Array()'
f.push("one");
bar(f);
alert(f.length); // alerts "2"

function bar(a) {
 a.push("two"); // Here, 'a' and 'f' point to the **same** array
}

Там, предупреждение показывает "2", а не "1", так как код в bar функции добавляется в массив, с помощью a качестве ссылки в списке аргументов, который указывал на тот же массив, что и f ссылка.

JavaScript имеет типы объектов (ака ссылочных типов) и примитивы. Строки и числа являются примитивами, они фактически хранятся в памяти, назначенной переменной. Почти все остальное - это объект, где переменная содержит ссылку на объект, а не копию самого объекта. Так:

var a = 1;
var b = a;
b = 2;
alert(a); // "1"
alert(b); // "2"

a и b имеют копии примитивного числа 1. Но:

var c = {prop: "value"};
var d = c;
d.prop = "updated value";
alert(c.prop); // "updated value"

Там c и d указывают на один и тот же объект, поэтому изменения объекта очевидны независимо от того, с какой ссылкой на него (c или d) вы смотрите на него.

И, конечно же,

var e = {prop: "foo"};
var f = {prop: "foo"};
f.prop = "bar";
alert(e.prop); // "foo"

Так как e и f указывают на разные объекты, изменения в них не влияют друг на друга.

Ключом к тому, чтобы держать это прямо, является мысль о том, что ссылка (а не объект) является примитивным значением. Ссылка - это просто произвольная вещь, которая позволяет вам искать объект в таблице. Итак, пока это:

var a = 1;

... дает это в памяти:

+-------+
| a |
+-------+
| 1 |
+-------+

...это:

var c = {prop: "value"};

... дает следующее:

+-------+
| c |
+-------+ +---------------+
| ref |------------->| prop: "value" |
+-------+ +---------------+

Следовательно, это:

var a = 1;
var b = a;

... дает:

+-------+
| a |
+-------+
| 1 |
+-------+

+-------+
| b |
+-------+
| 1 |
+-------+

...но это:

var c = {prop: "value"};
var d = c;

... дает следующее:

+-------+
| c |
+-------+
| ref |----\
+-------+ |
 |
 | +---------------+
 |------>| prop: "value" |
 | +---------------+
+-------+ |
| d | |
+-------+ |
| ref |----/
+-------+

Ссылка - это то, что удерживают переменные, а не объект. Ссылки - это примитивы, указывающие на объекты.

Так что вы с этим поделаете? В большинстве случаев это то, что вы хотите, потому что большую часть времени вы хотите передавать ссылки и ссылаться на исходный объект. Но иногда вы хотите фактически скопировать объект.

С массивами, это легко: используйте Array#slice проходящий в 0 для первого аргумента и второй аргумент:

var a = [1, 2, 3]; // An array containing 1, 2, and 3
alert(a.length); // "3"
var b = a.slice(0); // Copy it
alert(b.length); // "3"
b.push(4); // Add a fourth element
alert(b.length); // "4", it *has* changed
alert(a.length); // "3", it hasn't changed

Array#slice создает новый массив и копирует элементы из исходного массива в него, начиная с указанного вами элемента. Поскольку мы говорим 0, он копирует весь массив. Обратите внимание, что это мелкая копия, если какая-либо из записей массива является ссылкой на объект, так же как и с a = b; , ссылка копируется, а не объект.


Это происходит потому, что эти две переменные указывают на один и тот же массив. Чтобы этого избежать, если вы хотите назначить копию AnotherArray для buffer, вы можете использовать slice():

var buffer = AnotherArray.slice();


buffer - это ссылка на AnotherArray, другое имя для одного и того же объекта в памяти.

Это похоже на обращение к человеку, использующему полное имя или псевдоним - оба способа могут использоваться для доступа к экземпляру человека.


var buffer = new Array();

Создает новый массив и делает buffer пунктом.

buffer = AnotherArray;

Делает buffer точку для массива, на который AnotherArray, поэтому buffer и AnotherArray указывают на тот же массив. Это по дизайну, так как большую часть времени вы не хотите справляться с проблемой копирования объекта (или, особенно, функции), что является огромной потерей памяти.


Происходит несколько вещей...

var buffer = new Array(); // A new, empty array is created. It is
 // accessed via buffer

buffer = AnotherArray; // Remember that new array that buffer pointed to?
 // It now gone, and will be garbage collected.
 //
 // Now buffer is a second reference to AnotherArray.
 // Any changes to AnotherArray are now also changes
 // to buffer. Both buffer and AnotherArray are
 // references to a single array in memory.

licensed under cc by-sa 3.0 with attribution.