Как поменять две переменные в JavaScript

Ответы:

321

Вот одна строка для обмена значениями двух переменных.
Заданы переменные aи b:

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

Демонстрация ниже:

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
источник
264
+1. Но самая короткая версия будет в ECMAScript 6: [a, b] = [b, a];.
dfsq
8
@Kay: кажется, что гораздо медленнее использовать массив вместо третьей переменной: http://jsperf.com/swap-array-vs-variable Хотя я проверял это только в Chrome. Я еще не смог протестировать версию ECMAScript 6, так как в настоящее время она выдает Invalid left-hand side in assignment ошибку.
Нет
2
@ FrancoisWahl Хороший вопрос. Я думаю, что большинство ответов здесь будут работать и довольно эквивалентны. Я предполагаю, что это компромисс между временным использованием переменных, количеством кода и скоростью.
showdev
3
@ FrançoisWahl хорошо, я бы не догадался, что это решение намного медленнее. Смотрите также: jsperf.com/swap-array-vs-variable/3
SE это зло
3
@showdev Прочитайте цитату Дейкстры в ответе Теда Хоппа.
Брайан МакКатчон
185

ES6 (Firefox и Chrome уже поддерживают его (сопоставление массивов назначений)):

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

Педро Хусто
источник
2
кто-нибудь знает название такого вида свопа в es6?
Дерек
6
@derek - я думаю, что это называется сопоставлением массивов , формой назначения деструктуризации .
Тед Хопп
4
Похоже, что это примерно в 35 раз медленнее, чем метод третьей переменной на nodejs 7.4.0 / win7 64. Но это точно.
MKEY
5
Начиная с версии 8.8 V8, замена переменных с деструктуризацией массива должна быть такой же быстрой, как и с временной переменной ( v8project.blogspot.com/2018/06/v8-release-68.html ).
Рубен Верборг
120

Ты можешь сделать это:

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

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

Поскольку это целые числа, вы также можете использовать любое количество хитрых трюков 1 для замены без использования третьей переменной. Например, вы можете использовать побитовый оператор 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);

Это называется алгоритм обмена XOR. Его теория действия описана в этой статье Википедии .

1 «Компетентный программист полностью осознает ограниченный размер своего собственного черепа. Поэтому он подходит к своей задаче с полным смирением и избегает хитрых уловок, таких как чума». - Эдсгер В. Дейкстра

Тед Хопп
источник
Xor будет работать с любым типом данных. Это трюк вычитания, который будет работать только с числами.
Роб Грант
11
@RobertGrant - Оператор xor в JavaScript преобразует свои операнды в 32-разрядные целые числа (используя ToInt32внутренний метод - см. Раздел 11.10 стандарта ECMAScript ). Он не дает правильных результатов для нецелых числовых значений. Он также преобразует нечисловые значения в 32-разрядные целые числа. Если вы начинаете с a = "hi"и b = "there", вы в конечном итоге с a == 0и b == 0.
Тед Хопп
1
Этот прием работает с любым типом данных, если вы не возражаете против целочисленного результата; значения автоматически приводятся к int32s. Это означает, что он может работать с числовыми строками, логическими (0/1), нулевыми (0) и пустыми массивами / объектами (0). Хотя исходный тип не сохраняется, так что затронутые логические значения не будут работать с typeof a == 'boolean'или a === false, например. Действительные числа работают, за исключением того, что они смещены к нулю, а не округлены до ближайшего целого числа.
Бежор
1
@Beejor - другими словами, он работает с любым типом данных, кроме (нет, если они не являются целочисленными значениями). В моей книге «своп» означает «конец каждой переменной со значением, которое имеет другая», а не «преобразование в int32 и затем своп».
Тед Хопп
@TedHopp Справедливо достаточно. Я имел в виду «работает» с точки зрения того факта, что вы можете использовать для этого любой тип данных, а не так, как это работает как хорошее своп-решение. Я согласен, что это не очень полезно в целом.
Beejor
58

Не используйте код ниже. Это не рекомендуемый способ обмена значениями двух переменных (для этого просто используйте временную переменную ). Это просто показывает трюк JavaScript.

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

a = b + (b=a, 0)

Работает в два этапа:

  • (b=a, 0)устанавливает bстарое значение aи дает0
  • a = b + 0устанавливает aстарое значениеb
Рубен Верборг
источник
5
Версия temp var немного быстрее, а также более общая и удобочитаемая. jsperf.com/swap-two-numbers-without-tmp-var/9
Сурьма
Что означает этот синтаксис ()? как это дает 0?
Пит Элвин
8
Оператор в скобках является оператором запятой ,, и он был перенесен для установки права приоритета. Оператор запятой оценивает оба своих аргумента (в этом случае b=aи 0) и возвращает последний (в этом случае 0). Так что здесь, это имеет эффект установки нового bна старое значение a, уступая при этом 0.
Рубен Верборг
6
Правильно ли я считаю, что это работает только для числовых значений? Вы не можете использовать это с, например, var a = "hello" b = "world" as a = "world0".
Крис Г.В. Грин
3
@ChrisGWGreen:a = b + (b=a, "")
19

Начиная с ES6, вы также можете поменять переменные более элегантно:

var a = 1,
    b = 2;

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

console.log('a:', a, 'b:', b); // a: 2 b: 1
Питер
источник
18

Вот одна строка, предполагающая aи bуже существующая и имеющая значения, которые необходимо поменять местами:

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

Как упомянул @Kay, на самом деле это работает лучше, чем в массиве (почти в 2 раза быстрее).

bobobobo
источник
1
Как и мой идеальный ответ, просто я предпочитаю не переопределять переменную a & b при замене, а использовать явное имя переменной "tmp". Нравится var a, b, tmp; a = 1:; b = 2; tmp=a, a=b, b=tmp; Личный вкус.
Джонни Вонг
10

Используйте третью переменную как это:

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

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

ДЕМО - Использование третьей переменной


Нет
источник
10

Метод ES6 +: начиная с ES6, вы можете поменять переменные более элегантно. Вы можете использовать деструктурирование сопоставления массива присваивания. Это просто var a = 10 b = 20;

[a, b] = [b, a]

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

Джалак Патолия
источник
10

Теперь вы можете, наконец, сделать:

let a = 5;
let b = 10;

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

console.log(a, b);

mehulmpt
источник
9

Вы можете использовать временную переменную подкачки или XOR.

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

Это просто базовая логическая концепция, которая работает на любом языке, поддерживающем операцию XOR.

редактировать: см. комментарии. Забыл сказать, что это работает точно только с целым числом. Предполагается целочисленные переменные из потока вопроса

Dmin
источник
16
Работает для программирования интервью и других общих дел пустяков. Обратите внимание, однако, что это довольно глупый способ поменять ценности в реальной жизни. Во-первых, в JS он работает только с целыми числами.
cHao
1
@ Кей Что ты имеешь в виду под "ненастоящей вещью за последние 30 лет?" Я использую побитовые операторы всякий раз, когда это имеет смысл, что на самом деле довольно часто (например, переключение неизвестного логического значения)
Бен Гарольд,
1
@cHao Битовый оператор постоянно (и безусловно) самый быстрый на моей машине: jsperf.com/swap-array-vs-variable/2
Бен Гарольд,
3
@php_surgeon Я немного изменил скрипку, чтобы компилятор не мог пометить переменные как мертвые. jsperf.com/swap-array-vs-variable/3 . Решение temp var теперь на 1/4 быстрее, чем решение xor swap
kay - SE это зло
1
@Kay В ситуациях, когда что-то стабильно, хорошо прокомментировано, самая быстрая техника и используется только в одном или двух местах, я не понимаю, почему это не будет хорошо в производственном коде. Битовые операции в общем являются сложной концепцией, поэтому, если код уже использует их несколько, сопровождающие должны все равно быть с ними знакомы. В большинстве случаев это явно перебор. Я просто думаю, что общие заявления не всегда полезны; у всего есть место, даже "goto" и "eval".
Beejor
8

Вы можете использовать назначение деструктурирования ES6 следующим образом:

let a = 10;
let b = 20;

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

console.log(a, b); // a = 20, b = 10
Мануэль Абаскаль
источник
7

Поскольку ваш вопрос был ценным «Только эти переменные, а не какие-либо объекты», ответ будет также ценным:

var a = 1, b = 2

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

это трюк

И, как сказал Родриго Ассис, он "может быть короче"

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

Демо: http://jsfiddle.net/abdennour/2jJQ2/

Абденнур ТУМИ
источник
1
Те же недостатки, что и у ответа @ DmiN.
Кей - SE это зло
где вы найдете неисправности? Это не почетно
Abdennour TOUMI
2
@AbdennourToumi Я думаю, что Кей имеет в виду тот факт, что ваш ответ работает только с целыми числами.
showdev
1
@showdev: Пожалуйста, прочитайте еще раз вопрос: «Только эти переменные, а не какие-либо объекты» .... мой ответ ценен как вопрос. Я прошу вас отметить комментарий. Я повторяю: это не почетно.
Abdennour TOUMI
1
Этот разговор странный. @AbdennourTOUMI - переменные не совпадают с целыми числами. У вас могут быть переменные, которые указывают на объекты, строки, функции, нуль и т. Д.
Роб Грант
6

ES6 Разрушение:

Используя массив: [a, b] = [b, a]; // my favorite

Используя объект: {a, b} = {a:b, b:a}; // not bad neither

Флавиен Волкен
источник
4

Как мы могли пропустить эти классические oneliners

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

И

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

Последний предоставляет глобальную переменную '_', но это не должно иметь значения, так как типичное соглашение javascript - это использовать его как переменную 'dont care'.

Теему Иконен
источник
1
Во втором опечатка. Это должно бытьa = (_=b,b=a,_);
Mageek
Что означает подчеркивание _? Почему оно не нуждается в декларации?
день
подчеркивание - это просто имя глобальной переменной, вы можете заменить его на любое допустимое. например, a = (justsomething = b, b = a, justsomething)
Теему Иконен
6
О нет, не используйте необъявленные магические переменные! Это верный путь к ужасным ошибкам в реальной жизни.
Ориадам
Любой, кто использует underscore.js , будет очень недоволен, если попробует второй.
Тед Хопп
3

Я вижу вид олимпиады по программированию здесь. Еще одно хитрое однострочное решение:

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

Скрипка: http://jsfiddle.net/cherniv/4q226/

Cherniv
источник
2
Не нужно использовать медленный arguments, просто сделайте b = (function (x){ return x; })(a, a=b).
Рубен Верборг
1
@RubenVerborgh да, но с аргументами мы не определяем третью переменную!
Чернов
1
Технически, argumentsсписок также будет переменной.
Рубен Верборг
1
Ну, вы назначаете aк arguments[0]пропусканием его в качестве параметра.
Рубен Верборг
1
@RubenVerborgh да, но вы не создаете argumentsи его назначение происходит "за кадром"
Чернов
3

Обмен одной строкой

a = a^b^(b^=(a^b));
Saruselvi
источник
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);

удалите или закомментируйте 2 // или и запустите с одним набором кода

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

Тилак Радж
источник
2

Мы можем поменять var следующим образом:

var val1 =  117,
    val2 = 327;

val2 = val1-val2; 
console.log(val2);
val1 = val1-val2;
console.log(val1);
val2 = val1+val2;
console.log(val2);
Мохаммед Джавед
источник
2

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

let a = 1;
let b = 2;
[b, a] = [a, b]  // a = 2, b = 1
Станислав Божанов
источник
1
let a = 2, b = 4;
[b, a] = [a, b];

более подробный подход будет

let a = 2, b = 4;
a = [a, b];
b = a[0];
a = a[1];
Эногве Виктор
источник
1

До ES5, чтобы поменять местами два числа, вы должны создать временную переменную, а затем поменять ее местами. Но в ES6 очень просто поменять два числа с помощью деструктуризации массива. Смотрите пример.

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
Авинаш Малхотра
источник
1

Потому что я слышал, что этот метод работает медленнее:

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

Если вы планируете хранить ваши переменные в объекте (или массиве), эта функция должна работать:

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

Использование:

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
источник
1

Мы можем использовать IIFE для замены двух значений без дополнительного параметра

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

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

Ганеш Пхирке
источник
1

Деструктуризация массива ES6 используется для замены двух переменных. См пример

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

Более простой способ возможен с:

x === 1и y === 2; Но после того, как деструктуризации, xесть y, то есть 2, и yесть x, то есть 1.

Криш Малхотра
источник
1

Поменять местами

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

Перестановка одной строки "используя массив"

[a, b] = [b, a]
HusseiELbadady
источник
-5

(функция (A, B) {b = A; a = B;}) (parseInt (a), parseInt (b));

Карлос Коррейя
источник