如何在JavaScript中交换两个变量


Answers:


321

这是交换两个变量的值的单行代码。
给定变量ab

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>


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
Nope

2
@FrançoisWahl好点。我认为这里的大多数答案都是有效的,并且相当等效。我想这是在临时变量使用,代码量和速度之间进行权衡的问题。
showdev

3
@FrançoisWahl好吧,我不会猜到这个解决方案要慢得多。另请参见:jsperf.com/swap-array-vs-variable/3

3
@showdev阅读Ted Hopp答案中的Dijkstra报价。
Brian McCutchon '16

185

ES6(Firefox和Chrome已经支持它)(解构分配数组匹配):

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


2
有人知道es6中这种交换的名称吗?
derek

6
@derek-我认为这称为数组匹配,这是一种结构分配的形式。
Ted Hopp

4
这似乎比nodejs 7.4.0 / win7 64上的第三个变量方法慢约35倍。但是它确实很干净。
mkey


5
从V8版本6.8开始,使用数组解构的交换变量应与使用临时变量(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个 “有能力的程序员完全意识到自己头骨的尺寸有限。因此,他要谦卑地完成任务,并避免使用诸如瘟疫之类的巧妙技巧。” —埃格·迪克斯特拉(Edsger W. Dijkstra)


Xor将适用于任何数据类型。这是仅适用于数字的减法技巧。
罗伯·格兰特

11
@RobertGrant-JavaScript中的xor运算符将其操作数转换为32位整数(使用ToInt32内部方法,请参阅ECMAScript标准的11.10节)。对于非整数数值,它不会产生正确的结果。还将非数字值转换为32位整数。如果你开始a = "hi"b = "there"你结束了a == 0b == 0
泰德·霍普

1
只要您不介意整数结果,此技巧就适用于任何数据类型。这些值将自动广播到int32s。这意味着它可以使用数字字符串,布尔值(0/1),空值(0)和空数组/对象(0)。尽管未保留原始类型,但是例如受影响的布尔值不适用于typeof a == 'boolean'a === false。实数有效,只不过它们的底数是零而不是四舍五入到最接近的整数。
Beejor

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=a0),并返回最后一个(在这种情况下0)。因此,在这里,它的作用是将新b值设置为的旧值a,同时产生0
Ruben Verborgh 2014年

6
我认为这仅适用于数字值对吗?您不能将其与var a =“ hello” b =“ world”用作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

这是一个单线假设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; 个人品味。
约翰尼·王

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

现在,您终于可以执行以下操作:

let a = 5;
let b = 10;

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

console.log(a, b);


9

您可以使用临时交换变量或XOR。

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

这只是一个基本的逻辑概念,并且可以在支持XOR操作的每种语言中使用。

编辑:请参阅注释。忘了告诉我们这只能在整数时有效。假设来自问题线程的整数变量


16
用于编程采访和其他一般琐事案件。但是请注意,这是在现实生活中交换值的相当愚蠢的方法。一方面,在JS中,它仅适用于整数。
cHao 2013年

1
@Kay“过去30年来不是真品”是什么意思?每当有意义时,我都会使用按位运算符,这实际上很常见(例如,切换一个未知的布尔值)
Ben Harold

1
@cHao Bitwise运算符一直(到目前为止)在我的机器上一直是最快的:jsperf.com/swap-array-vs-variable/2
Ben Harold

3
@php_surgeon我稍微修改了小提琴,以便编译器无法将变量标记为无效。jsperf.com/swap-array-vs-variable/3。临时var解决方案现在比xor swap解决方案快1/4
凯-SE很邪恶

1
@Kay在某些稳定,注释完善,最快的技术并且仅在一个或两个地方使用的情况下,我不明白为什么在生产代码中它并不适合。通常,按位运算是一个很难理解的概念,因此,如果代码中已经使用了一堆运算符,则维护者无论如何都需要熟悉它们。在大多数情况下,这显然是矫kill过正。我只是认为笼统的声明并不总是有帮助的;一切都有一个地方,甚至是“ goto”和“ eval”。
Beejor


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 2013年

2
@AbdennourToumi我认为Kay是指您的答案仅适用于整数的事实。
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

我们怎么会错过这些经典的单线客

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)
Teemu Ikonen

6
哦,不,请不要使用未声明的magic-global var!这是解决现实生活中可怕错误的可靠方法。
oriadam

任何使用underscore.js的人都将不满意,如果他们尝试第二个。
泰德·霍普

3

我在这里看到一种编程奥林匹克。一种更棘手的单行解决方案:

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

小提琴:http : //jsfiddle.net/cherniv/4q226/


2
没必要用慢arguments,就做b = (function (x){ return x; })(a, a=b)
鲁本·沃博

1
@RubenVerborgh是的,但是带有参数,我们没有定义第三个变量!
切尔诺夫2013年

1
从技术上讲,该arguments列表也将是一个变量。
Ruben Verborgh

1
好吧,您a可以arguments[0]通过将其作为参数传递给它。
Ruben Verborgh 2013年

1
@RubenVerborgh是的,但是您没有创建,arguments并且其分配发生在“幕后”
Cherniv 2013年





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,要交换两个数字,您必须创建一个temp变量,然后交换它。但是在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];

如果您计划将var存储在对象(或数组)中,则此函数应该起作用:

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'}

1

我们可以使用IIFE交换两个值而无需额外的参数

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

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




By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.