วิธีการสลับสองตัวแปรใน JavaScript


171

ฉันมีตัวแปรสองตัวนี้:

var a = 1,
    b = 2;

คำถามของฉันคือวิธีการสลับพวกเขา? เฉพาะตัวแปรนี้ไม่ใช่วัตถุใด ๆ


คำตอบ:


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>


264
+1 แต่รุ่นที่สั้นที่สุดจะอยู่ใน ECMAScript [a, b] = [b, a];6:
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
kay - SE is evil

3
@showdev อ่านคำพูดของ Dijkstra ในคำตอบของ Ted Hopp
Brian McCutchon

185

ES6 (Firefox และ Chrome รองรับอยู่แล้ว (Destructuring Assignment Array Matching)):

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


2
ไม่มีใครรู้ชื่อของชนิดของการแลกเปลี่ยนใน es6?
ดีเร็ก

6
@derek - ฉันคิดว่ามันเรียกว่าอาร์เรย์ที่ตรงกับรูปแบบของการกำหนด destructuring
Ted Hopp

4
สิ่งนี้ดูเหมือนจะช้ากว่าวิธีตัวแปรที่สามประมาณ 35 เท่าใน nodejs 7.4.0 / win7 64 แต่ก็แน่ใจว่าเรียบร้อย
mkey

ขอบคุณสำหรับชื่อ developer.mozilla.org/en/docs/Web/JavaScript/Reference/…
Hritik

5
ตั้งแต่ V8 เวอร์ชัน 6.8 การสลับตัวแปรที่มีการทำลายอาร์เรย์ควรเร็วเท่ากับตัวแปรชั่วคราว ( v8project.blogspot.com/2018/06/v8-release-68.html )
Ruben Verborgh

120

คุณสามารถทำได้:

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

เพื่อความสามารถในการอ่านและการบำรุงรักษาไม่สามารถเอาชนะได้ (อย่างน้อยใน JavaScript) ทุกคนที่รักษารหัส (รวมถึงคุณหกเดือนนับจากนี้) จะรู้ว่าสิ่งที่เกิดขึ้น

เนื่องจากสิ่งเหล่านี้เป็นจำนวนเต็มคุณสามารถใช้เทคนิคฉลาด ๆ จำนวน1เพื่อสลับโดยไม่ต้องใช้ตัวแปรตัวที่สาม ตัวอย่างเช่นคุณสามารถใช้ตัวดำเนินการ bitor 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


แฮคเกอร์จะทำงานกับข้อมูลทุกชนิด มันเป็นเคล็ดลับการลบที่จะทำงานกับตัวเลขเท่านั้น
Rob Grant

11
@RobertGrant - ผู้ดำเนินการ xor ใน JavaScript แปลงตัวถูกดำเนินการเป็นจำนวนเต็ม 32 บิต (ใช้ToInt32วิธีการภายใน - ดูมาตรา 11.10 ของมาตรฐาน ECMAScript ) มันไม่ได้สร้างผลลัพธ์ที่ถูกต้องสำหรับค่าตัวเลขที่ไม่ใช่จำนวนเต็ม นอกจากนี้ยังแปลงค่าที่ไม่ใช่ตัวเลขเป็นจำนวนเต็ม 32 บิต หากคุณเริ่มต้นด้วยa = "hi"และb = "there"คุณจะจบลงด้วยและa == 0 b == 0
Ted Hopp

1
เคล็ดลับนี้ใช้ได้กับประเภทข้อมูลใด ๆ โดยที่คุณไม่ต้องสนใจผลลัพธ์ที่เป็นจำนวนเต็ม ค่าจะถูกแปลงโดยอัตโนมัติเป็น int32s ซึ่งหมายความว่าสามารถทำงานกับสตริงตัวเลข Booleans (0/1) null (0) และอาร์เรย์ / วัตถุว่าง (0) แม้ว่ารูปแบบดั้งเดิมจะไม่ได้รับการเก็บรักษาไว้ดังนั้น Booleans ที่ได้รับผลกระทบจะไม่ทำงานtypeof a == 'boolean'หรือa === falseตัวอย่างเช่น ตัวเลขจริงทำงานได้ยกเว้นว่าพวกมันจะปูไปทางศูนย์และถูกปัดเศษเป็นจำนวนเต็มที่ใกล้เคียงที่สุด
Beejor

1
@Beejor - กล่าวอีกนัยหนึ่งมันใช้งานได้กับชนิดข้อมูลใด ๆ ยกเว้นว่าจะไม่ได้ (เว้นแต่จะเป็นค่าจำนวนเต็ม) ในหนังสือของฉัน "swap" หมายถึง "ลงท้ายด้วยตัวแปรแต่ละตัวที่มีค่าที่อีกตัวหนึ่งมี" ไม่ใช่ "แปลงเป็น int32 แล้วสลับ"
Ted Hopp

@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
Antimony

ไวยากรณ์นี้ () หมายความว่าอย่างไร มันให้ผลเป็น 0 ได้อย่างไร?
Pete Alvin

8
โอเปอเรเตอร์ในวงเล็บคือโอเปอเรเตอร์คอมม่า,และมันถูกห่อเพื่อตั้งค่าลำดับความสำคัญก่อนหน้านี้ ตัวดำเนินการคอมม่าประเมินทั้งอาร์กิวเมนต์ (ในกรณีนี้b=aและ0) และส่งกลับค่าสุดท้าย (ในกรณีนี้0) ดังนั้นที่นี่มันมีผลกระทบของการตั้งค่าใหม่bเป็นค่าเก่าในขณะที่ผลผลิตa 0
Ruben Verborgh

6
ฉันคิดถูกแล้วว่ามันใช้ได้กับค่าตัวเลขเท่านั้น? คุณไม่สามารถใช้สิ่งนี้ด้วยเช่น var a = "hello" b = "world" เป็น a = "world0"
Chris GW Green

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 เท่าเร็ว)


1
เช่นเดียวกับคำตอบในอุดมคติของฉันฉันไม่ชอบการประกาศตัวแปร a & b ใหม่เมื่อทำการสลับและใช้ชื่อตัวแปรที่ชัดเจนว่า "tmp" ไลค์: var a, b, tmp; a = 1; b = 2; tmp=a, a=b, b=tmp; รสนิยมส่วนตัว.
Johnny Wong

10

ใช้ตัวแปรตัวที่สามเช่นนี้

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

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

DEMO - ใช้ตัวแปรตัวที่สาม



10

วิธี ES6 +: ตั้งแต่ ES6 คุณสามารถสลับตัวแปรได้อย่างสวยงามยิ่งขึ้น คุณสามารถใช้การจับคู่อาร์เรย์การกำหนดค่าการทำลาย มันเป็นเรื่องง่าย var a = 10 b = 20;

[a, b] = [b, a]

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



9

คุณสามารถใช้ตัวแปร swap ชั่วคราวหรือ XOR

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

นี่เป็นเพียงแนวคิดพื้นฐานเชิงตรรกะและทำงานในทุกภาษาที่สนับสนุนการดำเนินการ XOR

แก้ไข:ดูความคิดเห็น ลืมที่จะบอกว่าวิธีนี้ใช้ได้กับจำนวนเต็มเท่านั้น สันนิษฐานว่าตัวแปรจำนวนเต็มจากเธรดของคำถาม


16
ทำงานสำหรับการสัมภาษณ์การเขียนโปรแกรมและกรณีทั่วไปเรื่องไม่สำคัญอื่น ๆ แต่โปรดทราบว่านี่เป็นวิธีที่ค่อนข้างโง่ในการสลับค่าในชีวิตจริง สำหรับสิ่งหนึ่งใน JS ใช้งานได้กับจำนวนเต็มเท่านั้น
cHao

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 วิธีแก้ปัญหา temp var ตอนนี้ 1/4 เร็วกว่าโซลูชันของ xor swap
kay - SE นั้นชั่วร้าย

1
@ Kay ในสถานการณ์ที่มีบางสิ่งบางอย่างที่มีความเสถียรความเห็นดีเทคนิคที่เร็วที่สุดและใช้ในที่เดียวหรือสองแห่งฉันไม่เห็นว่าทำไมรหัสคงไม่ดีนัก โดยทั่วไปการใช้งาน Bitwise เป็นแนวคิดที่ยากดังนั้นหากรหัสใช้กลุ่มของพวกเขาอยู่แล้วผู้ดูแลจะต้องคุ้นเคยกับพวกเขาอยู่ดี สำหรับกรณีส่วนใหญ่จะเห็นได้ชัดเกินไป ฉันแค่คิดว่างบแบบผ้าห่มไม่ได้มีประโยชน์เสมอไป ทุกอย่างมีสถานที่แม้กระทั่ง "goto" และ "eval"
Beejor


7

เนื่องจากคำถามของคุณมีค่า "เฉพาะตัวแปรนี้เท่านั้นไม่มีวัตถุใด ๆ " คำตอบจะมีค่าเช่นกัน:

var a = 1, b = 2

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

มันเป็นกลอุบาย

และอย่างที่ Rodrigo Assis พูดมัน "อาจสั้นกว่านี้"

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

การสาธิต: http://jsfiddle.net/abdennour/2jJQ2/


1
ความผิดพลาดเช่นเดียวกับคำตอบของ @ DmiN
kay - SE ชั่ว

คุณพบข้อบกพร่องที่ไหน ไม่น่านับถือ
Abdennour TOUMI

2
@AbdennourToumi ฉันคิดว่า Kay หมายถึงความจริงที่ว่าคำตอบของคุณใช้ได้กับเลขจำนวนเต็มเท่านั้น
showdev

1
@showdev: โปรดอ่านคำถามอีกครั้ง: "เฉพาะตัวแปรนี้ไม่ใช่วัตถุใด ๆ " .... คำตอบของฉันมีค่าเป็นคำถาม ฉันขอให้คุณตั้งค่าสถานะความคิดเห็นฉันทำซ้ำ: มันไม่ได้เป็นเกียรติ
Abdennour TOUMI

1
บทสนทนานี้แปลกประหลาด @AbdennourTOUMI - ตัวแปรไม่เหมือนกับเลขจำนวนเต็ม คุณสามารถมีตัวแปรที่ชี้ไปยังวัตถุ, สตริง, ฟังก์ชั่น, โมฆะ ฯลฯ
Rob Grant


4

เราจะคิดถึงผู้เลียนแบบคลาสสิคเหล่านี้ได้อย่างไร

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

และ

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

อันสุดท้ายเผยให้เห็นตัวแปรทั่วโลก '_' แต่ที่ไม่ควรจะเป็นตามแบบแผนจาวาสคริปต์ทั่วไปคือการใช้มันเป็นตัวแปร 'ไม่สนใจ'


1
มีการพิมพ์ผิดในครั้งที่สอง มันควรจะเป็นa = (_=b,b=a,_);
จิ

ขีดล่าง_หมายถึงอะไร ทำไมมันไม่จำเป็นต้องประกาศ?
วันที่

ขีดล่างเป็นเพียงชื่อตัวแปรส่วนกลางคุณสามารถแทนที่ด้วยชื่อที่ถูกต้อง เช่น a = (justsomething = b, b = a, justsomething)
Teemu Ikonen

6
โอ้ไม่ใช้เวทมนต์ระดับโลกที่ไม่ได้ประกาศ! นั่นเป็นวิธีที่แน่นอนในการกำจัดแมลงที่น่ากลัวในชีวิตจริง
oriadam

ใครก็ตามที่ใช้underscore.jsจะไม่มีความสุขมากหากลองใช้ครั้งที่สอง
Ted Hopp

3

ฉันเห็นชนิดของการเขียนโปรแกรม olympiad ที่นี่ โซลูชันบรรทัดเดียวที่ซับซ้อนยิ่งขึ้น:

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

ซอ: http://jsfiddle.net/cherniv/4q226/


2
ไม่จำเป็นต้องใช้ช้าเพียงแค่ทำarguments b = (function (x){ return x; })(a, a=b)
Ruben Verborgh

1
@ RubenVerborgh ใช่ แต่ด้วยการโต้แย้งเราไม่ได้นิยามตัวแปรที่สาม!
Cherniv

1
ในทางเทคนิคargumentsรายการก็จะเป็นตัวแปร
Ruben Verborgh

1
คุณกำหนดaให้arguments[0]โดยผ่านมันเป็นพารามิเตอร์
Ruben Verborgh

1
@RubenVerborgh ใช่ แต่คุณไม่ได้สร้างargumentsและการมอบหมายของมันเกิดขึ้น "เบื้องหลัง"
Cherniv


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

จนถึง 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];

หากคุณวางแผนที่จะเก็บ vars ของคุณไว้ในวัตถุ (หรืออาร์เรย์) ฟังก์ชั่นนี้จะทำงาน:

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

การทำลายอาร์เรย์ ES6 ใช้เพื่อสลับสองตัวแปร ดูตัวอย่าง

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

ใช้วิธีที่ง่ายกว่าด้วย:

x === 1และy === 2; แต่หลังจาก destructuring, xเป็นyเช่น2และyเป็นเช่นx1



โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.