Поменяйте местами целые массивы в Javascript

Когда я пытаюсь создать функцию для замены двух массивов, исходные массивы остаются неизменными.

function swap(x, y) {
    var temp = x; x = y; y = temp;
}

u=[1, 0];
v=[0, 1];
swap(u, v);
console.log(u);
console.log(v);

Это приводит к u как [1, 0] и v как [0, 1]. Значения не были изменены после вызова функции swap.

С другой стороны, если я сделаю это без вызова функции:

u=[1, 0];
v=[0, 1];
var temp = u;
u = v;
v = temp;
console.log(u);
console.log(v);

Тогда они поменялись местами правильно, с u как [0, 1] и v как [1, 0].

Я думал, что массивы Javascript передаются по ссылке, а не по значению. Я что-то здесь неправильно понимаю?

6 ответов

Решение

Они передаются по ссылке, но они также присваиваются по ссылке. Когда ты пишешь x = y вы не модифицируете ни один из массивов, вы просто делаете локальную переменную x ссылаются на тот же массив, что и y,

Если вы хотите поменять содержимое массива, вы должны изменить сами массивы:

function swap(x,y) {
    var temp = x.slice(0);
    x.length = 0;
    [].push.apply( x, y );
    y.length = 0;
    [].push.apply( y, temp ); 
}

Javascript не имеет возможности передать ссылку на u а также v сами переменные. Таким образом, нет назначения x или же y в вашем swap() функция изменит то, что назначено u или же v, Javascript передает ссылку на объект, который u а также v держать. Таким образом, вы не можете изменить u а также v переменные изнутри swap(), Вы можете изменить содержимое объекта, на который они указывают, и, таким образом, свойства объекта, u а также v указать можно изменить.

Так как у меня есть фон C/C++, я думаю о том, что делает Javascript при передаче объектов как "передача по указателю". Когда вы звоните swap(u, v)что передается swap() Функция является указателем на массив, который u также указывает на. Итак, теперь у вас есть две переменные u а также x оба "указывают" на один и тот же массив. Таким образом, если вы измените этот фактический массив, то с u указывает на тот же массив, оба увидят модификацию. Но ничего, что вы делаете внутри swap() функция может изменить какой объект u или же v на самом деле указывают на.


В Javascript единственный способ изменить объект, на который указывают исходные переменные, - сделать их свойствами объекта и передать объект следующим образом:

function swap(obj, x, y) {
    var temp = obj[x]; obj[x] = obj[y]; obj[y] = temp;
}

var container = {};
container.u = [1, 0];
container.v = [0, 1];
swap(container, "u", "v");
console.log(container.u);
console.log(container.v);

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

 function swap(x, y) {
      // remove all elements from x into a temporary array
      var temp = x.splice(0, x.length);
      // then copy y into x
      x.push.apply(x, y);
      // clear y, then copy temp into it
      y.length = 0;
      y.push.apply(y, temp);
 }

Получить терминологию по этим вопросам "ссылка / ценность" сложно, но я сделаю все возможное.

То, что у вас есть для ваших переменных Object / Array, на самом деле просто ссылки. В отличие от C++, выражение "x = y" фактически не копирует переменные объекта в новое место в памяти. Внутренне это просто копирование указателя. Язык не имеет конструкций для "автоматического воссоздания" чего-то вроде объекта или массива в новом экземпляре; если по какой-то причине вы хотите сохранить две копии массива, вам нужно явно создать его, а затем скопировать значения (т. е. = []; или же = new Array(); или функция копирования, как = oldArray.map(...))

Небольшой пример кода, который может концептуально помочь. Эти же правила применяются между объектами и массивами.

a = {}; // In case you haven't seen it, this is like shorthand of "new Object();"
b = {};
c = b;
console.log(a === b); // false
console.log(b === c); // true
b.property = "hello";
console.log(c.property) // hello

Как и в Java, JavaScript является только передачей по значению. Присвоение локальных переменных в функции никогда не влияет ни на что, кроме функции.

Февраль 2022 г. Решение для замены всего содержимого массива 2.

Вы можете использовать деструктурирование для замены двух массивов:

      let a = [  1,  2,  3, 4 ];
let b = ['a','b','c','d'];

[a,b] = [b,a];   // swap

console.log(a);  // ["a", "b", "c", "d"]
console.log(b);  // [1, 2, 3, 4, 5]

Чтобы поменять местами 2 массива, вы можете использовать

Версия 1

      let arrA = [1,2,3,4];
let arrB = ['Eve', 'Bar', 'Foo'];

let tempArr = [arrA, arrB];  // constructing new array
arrA = tempArr [1];
arrB = tempArr [0];

Версия 1 (укороченная)

      let arrA = [1,2,3,4];
let arrB = ['Eve', 'Bar', 'Foo'];
    
// RHS : construction a new array 
// LHS : destruction of array
[arrB, arrA ] = [arrA, arrB];  

Версия 2 (оператор спреда)

      let arrA = [1,2,3,4];
let arrB = ['Eve', 'Bar', 'Foo'];

let arrC = [...arrB]
arrB = [...arrA]
arrA = [...arrC]
Другие вопросы по тегам