Cách trao đổi hai biến trong JavaScript


Câu trả lời:


321

Đây là một lớp lót để trao đổi các giá trị của hai biến.
Các biến đã cho ab:

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

Trình diễn dưới đây:

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. Nhưng phiên bản ngắn nhất sẽ có trong ECMAScript 6 : [a, b] = [b, a];.
dfsq

8
@Kay: Dường như cũng chậm hơn nhiều khi sử dụng một mảng thay vì biến thứ ba: http://jsperf.com/swap-array-vs-variable Tôi chỉ thử nghiệm điều này trong Chrome. Tôi chưa thể kiểm tra phiên bản ECMAScript 6 vì hiện tại nó đã Invalid left-hand side in assignment báo lỗi.
Không có

2
@ FrançoisWahl Điểm tốt. Tôi nghĩ rằng hầu hết các câu trả lời ở đây sẽ hoạt động và tương đối giống nhau. Tôi cho rằng đó là sự đánh đổi giữa việc sử dụng biến tạm thời, số lượng mã và tốc độ.
showdev

3
@ FrançoisWahl tốt, tôi sẽ không đoán được rằng giải pháp này chậm hơn nhiều. Xem thêm: jsperf.com/swap-array-vs-variable/3
kay - SE là ác

3
@showdev Đọc đoạn trích Dijkstra trong câu trả lời của Ted Hopp.
Brian McCutchon

185

ES6 (Firefox và Chrome đã hỗ trợ nó (Kết hợp mảng phân công chuyển nhượng)):

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


2
có ai biết tên của loại trao đổi như vậy trong es6 không?
derek

6
@derek - Tôi nghĩ nó được gọi là khớp mảng , một hình thức phân công phá hủy .
Ted Hopp

4
Điều này dường như chậm hơn khoảng 35 lần so với phương thức biến thứ ba trên nodejs 7.4.0 / win7 64. Nhưng nó chắc chắn là gọn gàng.
mkey


5
Kể từ phiên bản V8 6.8, việc hoán đổi các biến với phá hủy mảng sẽ nhanh như với một biến tạm thời ( v8project.blogspot.com/2018/06/v8-release-68.html ).
Ruben Verborgh

120

Bạn có thể làm được việc này:

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

Để dễ đọc và duy trì, điều này không thể đánh bại (ít nhất là trong JavaScript). Bất cứ ai duy trì mã (bao gồm cả bạn sáu tháng kể từ bây giờ) sẽ biết chính xác những gì đang diễn ra.

Vì đây là các số nguyên, bạn cũng có thể sử dụng bất kỳ số mẹo thông minh 1 nào để trao đổi mà không cần sử dụng biến thứ ba. Chẳng hạn, bạn có thể sử dụng toán tử xwise bitwise:

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);

Đây được gọi là thuật toán hoán đổi XOR. Lý thuyết hoạt động của nó được mô tả trong bài viết Wikipedia này .

1 "Lập trình viên có năng lực nhận thức đầy đủ về kích thước hạn chế của hộp sọ của chính anh ta. Do đó, anh ta tiếp cận nhiệm vụ của mình với sự khiêm tốn hoàn toàn, và tránh các thủ thuật thông minh như bệnh dịch hạch." - Edsger W. Dijkstra


Xor sẽ làm việc với bất kỳ loại dữ liệu. Đó là thủ thuật trừ sẽ chỉ hoạt động với các con số.
Rob Grant

11
@RobertGrant - Toán tử xor trong JavaScript chuyển đổi các toán hạng của nó thành các số nguyên 32 bit (sử dụng ToInt32phương thức bên trong, xem phần 11.10 của tiêu chuẩn ECMAScript ). Nó không tạo ra kết quả chính xác cho các giá trị số không nguyên. Nó cũng chuyển đổi các giá trị không số thành số nguyên 32 bit. Nếu bạn bắt đầu với a = "hi"b = "there", bạn kết thúc với a == 0b == 0.
Ted Hopp

1
Thủ thuật này hoạt động với bất kỳ loại dữ liệu nào, miễn là bạn không bận tâm đến kết quả số nguyên; các giá trị được tự động chuyển thành int32s. Điều này có nghĩa là nó có thể hoạt động với các chuỗi số, Booleans (0/1), null (0) và mảng / đối tượng trống (0). Mặc dù loại ban đầu không được bảo tồn, do đó, Booleans bị ảnh hưởng sẽ không hoạt động với typeof a == 'boolean'hoặc a === false, ví dụ. Các số thực hoạt động, ngoại trừ chúng trôi về 0 so với làm tròn đến số nguyên gần nhất.
Beejor

1
@Beejor - Nói cách khác, nó hoạt động với bất kỳ loại dữ liệu nào, ngoại trừ nó không (trừ khi chúng là các giá trị nguyên). Trong cuốn sách của tôi, "hoán đổi" có nghĩa là "kết thúc với mỗi biến có giá trị mà biến kia có", chứ không phải "chuyển đổi thành int32 và sau đó trao đổi".
Ted Hopp

@TedHopp Đủ công bằng. Tôi có nghĩa là "hoạt động" về mặt thực tế là bạn có thể ném bất kỳ loại dữ liệu nào vào nó, chứ không phải trong đó là một giải pháp trao đổi tốt. Tôi đồng ý rằng nó không hữu ích nói chung.
Beejor

58

Đừng sử dụng mã dưới đây. Đây không phải là cách được đề xuất để trao đổi giá trị của hai biến (chỉ cần sử dụng biến tạm thời cho điều đó). Nó chỉ hiển thị một thủ thuật JavaScript.

Giải pháp này không sử dụng biến tạm thời, không mảng, chỉ một bổ sung và nhanh chóng . Trong thực tế, đôi khi nó nhanh hơn một biến tạm thời trên một số nền tảng .
Nó hoạt động cho tất cả các số, không bao giờ tràn và xử lý các trường hợp cạnh như Infinity và NaN.

a = b + (b=a, 0)

Nó hoạt động theo hai bước:

  • (b=a, 0)thiết lập bgiá trị cũ của avà sản lượng0
  • a = b + 0đặt athành giá trị cũ củab

5
Phiên bản temp var nhanh hơn một chút, cũng chung chung và dễ đọc hơn. jsperf.com/swap-two-numbers-without-tmp-var/9
Antimon

Cú pháp này () thậm chí có nghĩa là gì? làm thế nào nó mang lại 0?
Pete Alvin

8
Toán tử trong ngoặc là toán tử dấu phẩy ,và nó đã được gói để đặt quyền ưu tiên. Toán tử dấu phẩy đánh giá cả hai đối số của nó (trong trường hợp này b=a0) và trả về cuối cùng (trong trường hợp này 0). Vì vậy, ở đây, nó có tác dụng thiết lập cái mới bthành giá trị cũ của a, trong khi mang lại 0.
Ruben Verborgh

6
Tôi có đúng khi nghĩ rằng điều này chỉ hoạt động cho giá trị số? Bạn không thể sử dụng điều này với ví dụ var a = "hello" b = "world" as a = "world0".
Chris GW Green

3
@ChrisGWGreen:a = b + (b=a, "")

19

Kể từ ES6, bạn cũng có thể trao đổi các biến thanh lịch hơn:

var a = 1,
    b = 2;

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

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

18

Đây là một lớp lót, giả sử abtồn tại và có các giá trị cần được hoán đổi:

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

Như @Kay đã đề cập, điều này thực sự hoạt động tốt hơn so với cách mảng (gần gấp đôi tốc độ).


1
Giống như câu trả lời lý tưởng của tôi, chỉ là tôi không thích khai báo biến a & b khi hoán đổi và sử dụng tên biến rõ ràng "tmp". Thích : var a, b, tmp; a = 1; b = 2; tmp=a, a=b, b=tmp; Sở thích cá nhân.
Johnny Wong

10

Sử dụng biến thứ ba như thế này:

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

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

DEMO - Sử dụng biến thứ ba



10

Phương pháp ES6 +: Kể từ ES6, bạn có thể trao đổi các biến thanh lịch hơn. Bạn có thể sử dụng hủy kết hợp mảng gán. Nó đơn giản. var a = 10 b = 20;

[a, b] = [b, a]

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



9

Bạn có thể sử dụng biến trao đổi tạm thời hoặc XOR.

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

Đây chỉ là một khái niệm logic cơ bản và hoạt động trong mọi ngôn ngữ hỗ trợ hoạt động XOR.

chỉnh sửa: xem các bình luận. Quên nói rằng điều này chỉ hoạt động với số nguyên. Giả sử các biến số nguyên từ chuỗi câu hỏi


16
Làm việc cho các cuộc phỏng vấn lập trình và các trường hợp đố chung khác. Lưu ý, mặc dù, đây là một cách khá ngu ngốc để trao đổi giá trị trong cuộc sống thực. Đối với một điều, trong JS, nó chỉ hoạt động với số nguyên.
cHao

1
@Kay Ý bạn là gì khi "không phải là một điều thực sự trong 30 năm qua?" Tôi sử dụng các toán tử bitwise bất cứ khi nào nó có ý nghĩa, điều này thực sự khá thường xuyên (ví dụ như một boolean không xác định)
Ben Harold

1
@cHao Toán tử bitwise luôn ổn định (và cho đến nay) nhanh nhất trên máy của tôi: jsperf.com/swap-array-vs-variable/2
Ben Harold

3
@php_surgeon Tôi đã thay đổi fiddle một chút để trình biên dịch không thể đánh dấu các biến là chết. jsperf.com/swap-array-vs-variable/3 . Giải pháp temp var hiện nhanh hơn 1/4 so với giải pháp hoán đổi xor
kay - SE là ác

1
@Kay Trong tình huống có thứ gì đó ổn định, được bình luận tốt, kỹ thuật nhanh nhất và chỉ được sử dụng ở một hoặc hai nơi, tôi không hiểu tại sao nó sẽ không ổn trong mã sản xuất. Bitwise op nói chung là một khái niệm khó khăn, vì vậy nếu mã đã sử dụng một loạt chúng, các nhà bảo trì sẽ cần phải làm quen với chúng. Đối với hầu hết các trường hợp, nó rõ ràng là quá mức cần thiết. Tôi chỉ nghĩ rằng những tuyên bố về chăn không phải lúc nào cũng hữu ích; mọi thứ đều có một vị trí, thậm chí là "goto" và "eval".
Beejor


7

Vì câu hỏi của bạn rất quý giá "Chỉ có các biến này, không phải bất kỳ đối tượng nào.", Câu trả lời cũng sẽ rất quý giá:

var a = 1, b = 2

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

đó là một mánh khóe

Và như Rodrigo Assis đã nói, nó "có thể ngắn hơn"

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

Bản trình diễn: http://jsfiddle.net/abdennour/2jJQ2/


1
Lỗi tương tự như câu trả lời của @ DmiN.
kay - SE là ác

bạn tìm thấy lỗi ở đâu? Thật không vinh dự
Abdennour TOUMI

2
@AbdennourToumi Tôi nghĩ rằng Kay đang đề cập đến thực tế là câu trả lời của bạn chỉ hoạt động với số nguyên.
showdev

1
@showdev: Vui lòng đọc lại câu hỏi: "Chỉ các biến này, không phải bất kỳ đối tượng nào" .... câu trả lời của tôi là quý giá như câu hỏi. Tôi yêu cầu bạn gắn cờ bình luận. Tôi nhắc lại: Thật không vinh dự.
Abdennour TOUMI

1
Cuộc trò chuyện này thật kỳ quái. @AbdennourTOUMI - các biến không giống như số nguyên. Bạn có thể có các biến trỏ đến các đối tượng, chuỗi, hàm, null, v.v.
Rob Grant

6

Phá hủy ES6:

Sử dụng một mảng: [a, b] = [b, a]; // my favorite

Sử dụng một đối tượng: {a, b} = {a:b, b:a}; // not bad neither


4

Làm thế nào chúng ta có thể bỏ lỡ những oneliners cổ điển

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

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

Cái cuối cùng phơi bày biến toàn cục '_' nhưng điều đó không quan trọng vì quy ước javascript thông thường là sử dụng biến đó là biến 'không quan tâm'.


1
Có một lỗi đánh máy trong cái thứ hai. Nó nên làa = (_=b,b=a,_);
Mageek

Dấu gạch dưới _có nghĩa là gì? Tại sao nó không cần khai báo?
ngày

dấu gạch dưới chỉ là tên biến toàn cục, bạn có thể thay thế nó bằng bất kỳ tên hợp lệ nào. ví dụ: a = (jowers Something = b, b = a, jowers Something)
Teemu Ikonen

6
Ồ không, đừng sử dụng ma thuật toàn cầu chưa được khai báo! Đó là một cách chắc chắn cho những con bọ khủng khiếp trong cuộc sống thực.
oriadam

Bất cứ ai sử dụng underscore.js sẽ rất không hài lòng nếu họ thử cái thứ hai.
Ted Hopp

3

Tôi thấy loại lập trình olympiad ở đây. Thêm một giải pháp một dòng khó khăn nữa:

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

Câu đố: http://jsfiddle.net/cherniv/4q226/


2
Không cần sử dụng chậm arguments, chỉ cần làm b = (function (x){ return x; })(a, a=b).
Ruben Verborgh

1
@RubenVerborgh có nhưng với các đối số, chúng tôi không xác định biến thứ ba!
Cherniv

1
Về mặt kỹ thuật, argumentsdanh sách cũng sẽ là một biến.
Ruben Verborgh

1
Vâng, bạn gán ađến arguments[0]bằng cách đi qua nó như một tham số.
Ruben Verborgh

1
@RubenVerborgh có, nhưng bạn không tạo argumentsvà sự phân công của nó xảy ra "đằng sau hậu trường"
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);

xóa hoặc nhận xét 2 // hoặc của và chạy với một bộ mã

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


2

Chúng tôi có thể trao đổi var như thế này:

var val1 =  117,
    val2 = 327;

val2 = val1-val2; 
console.log(val2);
val1 = val1-val2;
console.log(val1);
val2 = val1+val2;
console.log(val2);

2

Trong ES6 bây giờ có phân công phá hủy và bạn có thể làm:

let a = 1;
let b = 2;
[b, a] = [a, b]  // a = 2, b = 1

1
let a = 2, b = 4;
[b, a] = [a, b];

một cách tiếp cận dài dòng hơn sẽ là

let a = 2, b = 4;
a = [a, b];
b = a[0];
a = a[1];


1

Cho đến ES5, để hoán đổi hai số, bạn phải tạo một biến tạm thời và sau đó trao đổi nó. Nhưng trong ES6, rất dễ dàng để hoán đổi hai số bằng cách sử dụng tính năng phá hủy mảng. Xem ví dụ.

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ởi vì tôi nghe thấy phương pháp này chạy chậm hơn:

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

Nếu bạn có kế hoạch lưu trữ các vars của bạn trong một đối tượng (hoặc mảng), chức năng này sẽ hoạt động:

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

Sử dụng:

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

Chúng ta có thể sử dụng IIFE để trao đổi hai giá trị mà không cần thêm tham số

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

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


1

Phá hủy mảng ES6 được sử dụng để trao đổi hai biến. Xem ví dụ

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

Cách dễ dàng hơn có thể với:

x === 1y === 2; Nhưng sau destructuring, xy, ví dụ 2, và yx, tức là 1.


1

Trao đổi bằng Bitwise

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

Hoán đổi dòng đơn "bằng cách sử dụng Mảng"

[a, b] = [b, a]

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.