Jak zamienić dwie zmienne w JavaScript

Odpowiedzi:

321

Oto jedna linijka służąca do zamiany wartości dwóch zmiennych.
Podane zmienne ai b:

b = [a, a = b][0];

Demonstracja poniżej:

var a=1,
    b=2,
    output=document.getElementById('output');

output.innerHTML="<p>Original: "+a+", "+b+"</p>";

b = [a, a = b][0];

output.innerHTML+="<p>Swapped: "+a+", "+b+"</p>";
<div id="output"></div>

showdev
źródło
264
+1. Ale najkrótsza wersja będzie w ECMAScript 6: [a, b] = [b, a];.
dfsq
8
@Kay: Wydaje się również, że działa znacznie wolniej, używając tablicy zamiast trzeciej zmiennej: http://jsperf.com/swap-array-vs-variable Testowałem to tylko w Chrome. Nie mogłem jeszcze przetestować wersji ECMAScript 6, ponieważ obecnie Invalid left-hand side in assignment wyświetla błąd.
Nie,
2
@ FrançoisWahl Słuszna uwaga. Myślę, że większość odpowiedzi tutaj zadziała i są dość równoważne. Przypuszczam, że jest to kompromis między tymczasowym użyciem zmiennych, ilością kodu i szybkością.
showdev
3
@ FrançoisWahl cóż, nie przypuszczałbym, że to rozwiązanie jest o wiele wolniejsze. Zobacz też: jsperf.com/swap-array-vs-variable/3
kay - SE is evil
3
@showdev Przeczytaj cytat Dijkstry w odpowiedzi Teda Hoppa.
Brian McCutchon
185

ES6 (Firefox i Chrome już to obsługują (Destruifying Assignment Array Matching)):

let a = 5, b = 6;
[a, b] = [b, a];
console.log(`${a} ${b}`);

Pedro Justo
źródło
2
ktoś zna nazwę tego rodzaju wymiany w es6?
derek
6
@derek - myślę, że to się nazywa dopasowywaniem tablic , forma przypisania destrukturyzacji .
Ted Hopp,
4
Wydaje się, że jest to około 35 razy wolniejsze niż metoda trzeciej zmiennej na nodejs 7.4.0 / win7 64. Ale na pewno jest fajna.
mkey
5
Od wersji V8 6.8, zamiana zmiennych ze zniszczeniem tablic powinna być tak szybka jak w przypadku zmiennej tymczasowej ( v8project.blogspot.com/2018/06/v8-release-68.html ).
Ruben Verborgh,
120

Możesz to zrobić:

var a = 1,
    b = 2,
    tmp;
tmp = a;
a = b;
b = tmp;

Jeśli chodzi o czytelność i łatwość konserwacji, nie można tego przebić (przynajmniej w JavaScript). Każdy, kto zajmuje się kodem (w tym Ty za sześć miesięcy), będzie dokładnie wiedział, co się dzieje.

Ponieważ są to liczby całkowite, możesz również użyć dowolnej liczby sprytnych sztuczek 1 do zamiany bez używania trzeciej zmiennej. Na przykład możesz użyć bitowego operatora xor:

let a = 1, b = 2;
a = a ^ b;
b = a ^ b;
a = a ^ b;
    
console.log('a is now:', a);
console.log('b is now:', b);

Nazywa się to algorytmem wymiany XOR. Jego teorię działania opisano w tym artykule w Wikipedii .

1 „Kompetentny programista jest w pełni świadomy ograniczonych rozmiarów własnej czaszki. Dlatego podchodzi do swojego zadania z pełną pokorą i unika sprytnych sztuczek, takich jak zaraza”. - Edsger W. Dijkstra

Ted Hopp
źródło
Xor będzie działał z każdym typem danych. To sztuczka odejmowania, która działa tylko z liczbami.
Rob Grant
11
@RobertGrant - Operator xor w JavaScript konwertuje swoje operandy na 32-bitowe liczby całkowite (przy użyciu ToInt32metody wewnętrznej - patrz Rozdział 11.10 standardu ECMAScript ). Nie daje poprawnych wyników dla wartości liczbowych innych niż całkowite. Konwertuje również wartości nienumeryczne na 32-bitowe liczby całkowite. Jeśli zaczniesz od a = "hi"i b = "there", otrzymasz a == 0i b == 0.
Ted Hopp,
1
Ta sztuczka działa z każdym typem danych, pod warunkiem, że nie masz nic przeciwko wynikowi w postaci liczby całkowitej; wartości są rzutowane automatycznie na int32s. Oznacza to, że może pracować z ciągami numerycznymi, wartościami logicznymi (0/1), null (0) i pustymi tablicami / obiektami (0). Chociaż oryginalny typ nie jest zachowywany, więc dotknięte wartości Booleans nie będą działać na przykład z typeof a == 'boolean'lub a === false. Liczby rzeczywiste działają, z wyjątkiem tego, że są wyliczane w kierunku zera w porównaniu z zaokrągleniem do najbliższej liczby całkowitej.
Beejor
1
@Beejor - Innymi słowy, działa z dowolnym typem danych, z wyjątkiem tego, że nie (chyba że są to wartości całkowite). W mojej książce „zamiana” oznacza „koniec z każdą zmienną mającą wartość, którą miała druga”, a nie „konwersja na int32, a następnie zamiana”.
Ted Hopp,
@TedHopp Fair wystarczająco. Miałem na myśli "działa" w kategoriach tego, że można do niego wrzucić dowolny typ danych, a nie jako dobre rozwiązanie do wymiany. Zgadzam się, że ogólnie nie jest to zbyt przydatne.
Beejor
58

Nie używaj poniższego kodu. To nie zalecanym sposobem, aby zamienić wartości dwóch zmiennych (wystarczy użyć zmiennej tymczasowej dla tego). Pokazuje tylko sztuczkę JavaScript.

To rozwiązanie nie wykorzystuje zmiennych tymczasowych, żadnych tablic, tylko jeden dodatek i jest szybkie . W rzeczywistości jest czasami szybszy niż zmienna tymczasowa na kilku platformach .
Działa dla wszystkich liczb, nigdy się nie przepełnia i obsługuje przypadki skrajne, takie jak Infinity i NaN.

a = b + (b=a, 0)

Działa w dwóch krokach:

  • (b=a, 0)ustawia bna starą wartość ai daje0
  • a = b + 0ustawia astarą wartośćb
Ruben Verborgh
źródło
5
Wersja temp var jest nieco szybsza i bardziej ogólna, a także bardziej czytelna. jsperf.com/swap-two-numbers-without-tmp-var/9
Antimony
Co w ogóle oznacza ta składnia ()? jak to daje 0?
Pete Alvin
8
Operator w nawiasach jest operatorem przecinka ,i został zawinięty w celu ustawienia prawa pierwszeństwa. Operator przecinka ocenia oba argumenty (w tym przypadku b=ai 0) i zwraca ostatni (w tym przypadku 0). Więc tutaj ma to wpływ na ustawienie nowej bwartości starej a, przy jednoczesnym uzyskaniu 0.
Ruben Verborgh
6
Czy mam rację, myśląc, że to działa tylko dla wartości liczbowych? Nie możesz tego używać z np. Var a = "hello" b = "world" as a = "world0".
Chris GW Green
3
@ChrisGWGreen:a = b + (b=a, "")
19

Od wersji ES6 możesz także zamieniać zmienne bardziej elegancko:

var a = 1,
    b = 2;

[a, b] = [b, a];

console.log('a:', a, 'b:', b); // a: 2 b: 1
Piotr
źródło
18

Oto jeden-liner, zakładając ai bjuż istnieją i mają wartości, która chciałaby zostać zamienione:

var c=a, a=b, b=c;

Jak wspomniał @Kay, w rzeczywistości działa to lepiej niż metoda tablicowa (prawie 2x szybciej).

bobobobo
źródło
1
Podobnie jak moja idealna odpowiedź, po prostu wolę nie deklarować ponownie zmiennej a & b podczas zamiany i używać jawnej nazwy zmiennej „tmp”. Jak var a, b, tmp; a = 1:; b = 2; tmp=a, a=b, b=tmp; Własny gust.
Johnny Wong
10

Użyj trzeciej zmiennej, takiej jak ta:

var a = 1,
    b = 2,
    c = a;

a = b; // must be first or a and b end up being both 1
b = c;

DEMO - Korzystanie z trzeciej zmiennej


nie
źródło
10

Metoda ES6 +: Od wersji ES6 można bardziej elegancko wymieniać zmienne. Możesz użyć destrukturyzacji dopasowywania tablic przypisania. Po prostu. var a = 10 b = 20;

[a, b] = [b, a]

console.log (a, b) // 20 10

Jalak Patoliya
źródło
10

Teraz możesz wreszcie zrobić:

let a = 5;
let b = 10;

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

console.log(a, b);

mehulmpt
źródło
9

Możesz użyć tymczasowej zmiennej wymiany lub XOR.

a = a ^ b
b = a ^ b
a = a ^ b

To tylko podstawowa koncepcja logiczna i działa w każdym języku obsługującym operacje XOR.

edycja: zobacz komentarze. Zapomniałem powiedzieć, że działa to na pewno tylko w przypadku liczby całkowitej. Założono zmienne całkowite z wątku pytania

DmiN
źródło
16
Działa na potrzeby wywiadów programistycznych i innych ogólnych spraw związanych z ciekawostkami. Pamiętaj jednak, że jest to raczej głupi sposób na zamianę wartości w prawdziwym życiu. Po pierwsze, w JS działa tylko z liczbami całkowitymi.
cHao
1
@Kay Co masz na myśli, mówiąc „coś nierealnego przez ostatnie 30 lat”? Używam operatorów bitowych, kiedy tylko ma to sens, co jest w rzeczywistości dość często (na przykład przełączanie nieznanej wartości logicznej)
Ben Harold
1
Operator @cHao Bitwise jest konsekwentnie (i zdecydowanie) najszybszy na moim komputerze: jsperf.com/swap-array-vs-variable/2
Ben Harold
3
@php_surgeon Zmieniłem trochę skrzypce, żeby kompilator nie mógł oznaczyć zmiennych jako martwych. jsperf.com/swap-array-vs-variable/3 . Rozwiązanie Temp Var jest teraz o 1/4 szybsze niż rozwiązanie XOR Swap
Kay - SE is evil
1
@Kay W sytuacjach, gdy coś jest stabilne, dobrze skomentowane, najszybsze i używane tylko w jednym lub dwóch miejscach, nie rozumiem, dlaczego nie byłoby to dobre w kodzie produkcyjnym. Generalnie operacje bitowe są trudną koncepcją, więc jeśli kod używa już ich kilku, opiekunowie i tak musieliby je znać. W większości przypadków jest to oczywiście przesada. Myślę tylko, że ogólne stwierdzenia nie zawsze są pomocne; wszystko ma swoje miejsce, nawet „goto” i „eval”.
Beejor
8

Możesz użyć przypisania niszczącego ES6 w następujący sposób:

let a = 10;
let b = 20;

[a, b] = [b, a]; 

console.log(a, b); // a = 20, b = 10
Manuel Abascal
źródło
7

Ponieważ Twoje pytanie było cenne „Tylko te zmienne, a nie żadne przedmioty”, odpowiedź również będzie cenna:

var a = 1, b = 2

a=a+b;
b=a-b;
a=a-b;

to sztuczka

I jak powiedział Rodrigo Assis, „może być krótsze”

 b=a+(a=b)-b;

Demo: http://jsfiddle.net/abdennour/2jJQ2/

Abdennour TOUMI
źródło
1
Te same błędy, co odpowiedź @ DmiN.
kay - SE is evil
gdzie znajdujesz usterki? To nie jest honorowe
Abdennour TOUMI
2
@AbdennourToumi Myślę, że Kay odnosi się do faktu, że twoja odpowiedź działa tylko w przypadku liczb całkowitych.
showdev
1
@showdev: Przeczytaj jeszcze raz pytanie: „Tylko te zmienne, a nie żadne obiekty”… moja odpowiedź jest cenna jak pytanie. Proszę o oznaczenie komentarza. Powtarzam: to nie jest honorowe.
Abdennour TOUMI
1
Ta rozmowa jest dziwna. @AbdennourTOUMI - zmienne nie są tym samym, co liczby całkowite. Możesz mieć zmienne, które wskazują na obiekty, ciągi znaków, funkcje, null itp.
Rob Grant
6

Destrukturyzacja ES6:

Korzystanie z tablicy: [a, b] = [b, a]; // my favorite

Korzystanie z obiektu: {a, b} = {a:b, b:a}; // not bad neither

Flavien Volken
źródło
4

Jak moglibyśmy przegapić te klasyczne onelinery

var a = 1, b = 2
a = ({a:b, _:(b=a)}).a;

I

var a = 1, b = 2
a = (_=b,b=a,_);

Ostatnia z nich ujawnia zmienną globalną „_”, ale nie powinno to mieć znaczenia, ponieważ typowa konwencja javascript polega na używaniu jej jako zmiennej „dont care”.

Teemu Ikonen
źródło
1
W drugim jest literówka. Powinno byća = (_=b,b=a,_);
Mageek
Co oznacza podkreślenie _? Dlaczego nie wymaga deklaracji?
dzień
podkreślenie to tylko nazwa zmiennej globalnej, możesz ją zastąpić dowolną poprawną. np. a = (justsomething = b, b = a, justsomething)
Teemu Ikonen
6
O nie, nie używaj niezadeklarowanych zmiennych magic-global! To pewny sposób na okropne błędy w prawdziwym życiu.
oriadam
Każdy, kto używa underscore.js, będzie bardzo nieszczęśliwy, jeśli spróbuje drugiego.
Ted Hopp
3

Widzę tu coś w rodzaju olimpiady programowania. Jeszcze jedno skomplikowane rozwiązanie jednowierszowe:

b = (function(){ a=b; return arguments[0]; })(a);

Skrzypce: http://jsfiddle.net/cherniv/4q226/

Czerniow
źródło
2
Nie musisz używać spowolnienia arguments, po prostu zrób b = (function (x){ return x; })(a, a=b).
Ruben Verborgh,
1
@RubenVerborgh tak, ale z argumentami nie definiujemy trzeciej zmiennej!
Czerniow
1
Z technicznego punktu argumentswidzenia lista byłaby również zmienną.
Ruben Verborgh
1
Cóż, przypisujesz ado arguments[0], przekazując go jako parametr.
Ruben Verborgh,
1
@RubenVerborgh tak, ale nie tworzysz, argumentsa jego przypisanie odbywa się „za kulisami”
Czerniow
3

Zamiana jednej linii

a = a^b^(b^=(a^b));
Saruselvi
źródło
3
var a = 5;
var b = 10;

b = [a, a = b][0];
//or
b = [a, a = b];
b = b[0];

//or
b = [a, b];
a = b[1];
b = b[0];


alert("a=" + a + ',' + "b=" + b);

usuń lub skomentuj dwa // lub i uruchom z jednym zestawem kodu

http://jsfiddle.net/USdv8/57/

Thilak Raj
źródło
2

Jesteśmy w stanie zamienić var ​​w ten sposób:

var val1 =  117,
    val2 = 327;

val2 = val1-val2; 
console.log(val2);
val1 = val1-val2;
console.log(val1);
val2 = val1+val2;
console.log(val2);
Mohammed Javed
źródło
2

W ES6 jest teraz destrukcyjne przypisanie i możesz:

let a = 1;
let b = 2;
[b, a] = [a, b]  // a = 2, b = 1
Stanislav Bozhanov
źródło
1
let a = 2, b = 4;
[b, a] = [a, b];

byłoby bardziej rozwlekłe podejście

let a = 2, b = 4;
a = [a, b];
b = a[0];
a = a[1];
Enogwe Victor
źródło
1

Do ES5, aby zamienić dwie liczby, musisz utworzyć zmienną tymczasową, a następnie zamienić ją. Ale w ES6 bardzo łatwo jest zamienić dwie liczby za pomocą destrukturyzacji tablic. Zobacz przykład.

let x,y;
[x,y]=[2,3];
console.log(x,y);      // return 2,3

[x,y]=[y,x];
console.log(x,y);      // return 3,2
Avinash Malhotra
źródło
1

Ponieważ słyszę, że ta metoda działa wolniej:

b = [a, a = b][0];

Jeśli planujesz przechowywać swoje vary w obiekcie (lub tablicy), ta funkcja powinna działać:

function swapVars(obj, var1, var2){
    let temp = obj[var1];
    obj[var1] = obj[var2];
    obj[var2] = temp;
}

Stosowanie:

let test = {a: 'test 1', b: 'test 2'};

console.log(test); //output: {a: 'test 1', b: 'test 2'}

swapVars(test, 'a', 'b');

console.log(test); //output: {a: 'test 2', b: 'test 1'}
SwiftNinjaPro
źródło
1

Możemy użyć IIFE do zamiany dwóch wartości bez dodatkowego parametru

var a = 5, b =8;
b = (function(a){ 
    return a 
}(a, a=b));

document.write("a: " + a+ "  b:  "+ b);

ganesh phirke
źródło
1

Destrukturyzacja tablicy ES6 jest używana do zamiany dwóch zmiennych. Zobacz przykład

var [x,y]=[1,2];
[x,y]=[y,x];

Łatwiej to możliwe dzięki:

x === 1i y === 2; Ale po destrukturyzacji xjest y, czyli 2i yjest x, tj 1.

Krish Malhotra
źródło
1

Zamień za pomocą Bitwise

let a = 10;
let b = 20;
a ^= b;
y ^= a;
a ^= b;

Zamiana jednej linii „przy użyciu tablicy”

[a, b] = [b, a]
HusseiELbadady
źródło
-5

(funkcja (A, B) {b = A; a = B;}) (parseInt (a), parseInt (b));

Carlos Correia
źródło