如何在JavaScript中交换两个变量

229

我有这两个变量:

var a = 1,
    b = 2;

我的问题是如何交换它们?仅限这些变量,而不是任何对象。


8
在计算机科学中,交换(Swap)是指将两个变量的值互换。使用一个临时变量可以轻松地实现这一操作。具体来说,我们可以将第一个变量的值存储在一个临时变量中,然后将第二个变量的值赋给第一个变量,最后将临时变量的值赋给第二个变量。这种方法适用于几乎所有编程语言。 - Kijewski
22个回答

357

以下是将两个变量的值交换的一行代码。
给定变量ab

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

下面是演示:

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

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

// swap values for variables "a" and "b"
b = [a, a = b][0];

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


345
最短的 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 错误。 - Nope
2
@FrançoisWahl 很好的观点。我认为这里的大多数答案都可以工作并且相当等效。我想这是在临时变量使用、代码量和速度之间做出权衡的结果。 - showdev
3
@FrançoisWahl 好的,我没想到这个解决方案会慢那么多。参见:http://jsperf.com/swap-array-vs-variable/3 - Kijewski
4
请阅读Ted Hopp答案中的Dijkstra引用。 - Brian McCutchon
显示剩余3条评论

284

ES6(Firefox和Chrome已支持它(Destructuring Assignment Array Matching)):

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


3
有人知道 ES6 中这种类型的交换叫什么名字吗? - derek
8
@Derek - 我认为这被称为“数组匹配”,是一种“解构赋值”的形式。链接为http://es6-features.org/#ArrayMatching和http://www.ecma-international.org/ecma-262/6.0/#sec-destructuring-assignment。 - Ted Hopp
6
这似乎比第三种变量方法慢了约35倍,在nodejs 7.4.0/win7 64上。但它确实很整洁。 - mkey
19
自从V8版本6.8起,使用数组解构交换变量的速度应该和使用临时变量一样快。(https://v8project.blogspot.com/2018/06/v8-release-68.html) - Ruben Verborgh
3
如果在[a, b] = [b, a]之前的行中省略了;,那么这里有一个陷阱:JS会做一些奇怪的事情™,可能是因为它与前一行合并为数组/对象索引或类似的东西。 - Martin Tournoij
显示剩余3条评论

133

您可以这样做:

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

为了提高可读性和可维护性,这是无与伦比的(至少在 JavaScript 中是如此)。任何维护代码的人(包括六个月后的您)都会清楚地知道正在发生什么。

由于这些是整数,您还可以使用许多巧妙的技巧1来在不使用第三个变量的情况下进行交换。例如,您可以使用按位异或运算符:

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"优秀的程序员完全意识到自己头脑的局限性。因此,他们以充分的谦虚态度来完成任务,并避免像瘟疫一样的聪明技巧。" — Edsger W. Dijkstra


Xor 可以适用于任何数据类型。而减法技巧只能适用于数字。 - Rob Grant
12
JavaScript中的异或运算符将其操作数转换为32位整数(使用 ToInt32 内部方法进行转换——请参见ECMAScript标准第11.10节)。它不能正确处理非整数数字值,并将非数字值转换为32位整数。如果你从 a = "hi"b = "there" 开始,最终结果是 a == 0b == 0 - Ted Hopp
1
这个技巧适用于任何数据类型,只要你不介意得到一个整数结果;值会自动转换为int32。这意味着它可以处理数字字符串、布尔值(0/1)、null(0)和空数组/对象(0)。虽然原始类型没有被保留,所以受影响的布尔值不能使用 typeof a == 'boolean'a === false 等方式进行判断。实数也可以工作,但它们向零取整而不是四舍五入到最近的整数。 - Beejor
1
@Beejor - 换句话说,它可以使用任何数据类型,除非它们是整数值(integer values)。在我的书里,“swap”意味着“以每个变量都具有对方原本拥有的值结束”,而不是“转换为int32然后交换”。 - Ted Hopp
@TedHopp 好的。我所说的“可行”是指你可以将任何数据类型传递给它,而不是它能作为一个好的交换解决方案。我同意它在一般情况下并不是非常有用。 - Beejor
我真的很喜欢这个答案中的Dijkstra引用! :-) - simbro

60

不要使用以下代码。 它不是推荐的交换两个变量值的方法(简单地使用一个临时变量)。 它只是展示了 JavaScript 的一个技巧。

这种解决方案不使用临时变量,也不使用数组,仅使用一次加法操作,并且速度很快。 实际上,在一些平台上,它甚至比临时变量更快
它适用于所有数字,永远不会溢出,并能处理诸如 Infinity 和 NaN 等边界情况。

a = b + (b=a, 0)

它分为两个步骤:

  • (b=a, 0)b 设置为旧的值a 并产生 0
  • a = b + 0a设置为旧的值b

5
使用临时变量的版本稍微更快,而且更通用和易读。http://jsperf.com/swap-two-numbers-without-tmp-var/9 - Antimony
这个()语法是什么意思?它怎么会产生0? - Pete Alvin
8
括号中的运算符是逗号运算符“,”,它被括起来以调整优先级。逗号运算符会评估它的两个参数(在这种情况下是b=a0),并返回最后一个(在这种情况下是0)。因此,在这里,它的作用是将新的b设置为旧的a值,同时返回0 - Ruben Verborgh
6
我理解您的意思是这只适用于数字值?您不能像 var a ="hello" b="world" 这样使用它,例如 a="world0"。 - Chris GW Green
3
@aaronlee: a = b + (b=a, "") - user1106925
显示剩余3条评论

21

现在你终于可以做到:

let a = 5;
let b = 10;

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

console.log(a, b);


21
自 ES6 起,您还可以更优雅地交换变量:
var a = 1,
    b = 2;

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

console.log('a:', a, 'b:', b); // a: 2 b: 1

19

假设ab已经存在并且需要交换值,这是一个一行代码的解决办法:

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

正如 @Kay 提到的那样,这种方法比数组方式表现得更好(快近 2 倍)。


1
喜欢我的理想答案,只是我更喜欢在交换时不重新声明变量a和b,并使用显式变量名“tmp”。像这样:
var a,b,tmp;
a = 1;
b = 2;
tmp=a,a=b,b=tmp; 个人口味。
- Johnny Wong

11

你可以使用一个临时交换变量或异或操作。

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

这只是一个基本的逻辑概念,在支持异或运算的每种语言中都可以使用。

编辑:请参见评论。我忘了告诉大家,这仅适用于整数。假设来自问题线程的整数变量。


19
适用于编程面试和其他一般的琐事情况。请注意,这是在现实生活中交换值的相当愚蠢的方法之一。对于JS来说,它仅适用于整数。 - cHao
1
@Kay,“在过去的30年中并不是真正的事情”,你是什么意思?每当它有意义时,我都会使用位运算符,这实际上很常见(例如切换未知布尔值)。 - Ben Harold
1
@php_surgeon:XOR交换已经很长一段时间没有用了。几十年来内存并不稀缺,现代CPU使用临时变量比使用XOR要更快。(寄存器的相互依赖关系使其难以进行流水线处理。)再加上它不太易读,所以:P - cHao
1
@cHao 在我的机器上,位运算符始终(且远远)是最快的:http://jsperf.com/swap-array-vs-variable/2 - Ben Harold
3
@php_surgeon 我稍微修改了这个示例代码,这样编译器就无法将变量标记为死代码。http://jsperf.com/swap-array-vs-variable/3。现在临时变量的解决方案比异或交换的解决方案快1/4。 - Kijewski
显示剩余5条评论

10

使用第三个变量如下:

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

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

演示 - 使用第三个变量



9
作为你珍贵的问题“只有这些变量,没有任何对象。”,答案也是珍贵的:
var a = 1, b = 2
a=a+b;
b=a-b;
a=a-b;

这是一个技巧

正如Rodrigo Assis所说,它“可以更短”

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

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


1
与 @DmiN 的答案相同的错误。 - Kijewski
2
@AbdennourToumi,我认为Kay指的是你的答案只适用于整数。 - showdev
1
@showdev:请再次阅读问题:“仅限这些变量,而不是任何对象”……我的回答与问题一样珍贵。我要求您标记此评论。我重申:这是不光彩的行为。 - Abdennour TOUMI
@AbdennourToumi 为了澄清,我只是在解释我认为Kay的意思。这与荣誉无关。 - showdev
2
这段对话很奇怪。@AbdennourTOUMI - 变量不同于整数。你可以有指向对象、字符串、函数、null等的变量。 - Rob Grant
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接