Reputation: 185913
So given a function
function foo( a, b ) {
}
Now, if I wanted to swap the values of the arguments a
and b
, I could write this:
var t = a;
a = b;
b = t;
However, this is an ugly pattern - it requires three statements (three lines of code), plus a local variable. Now, I could bear three statements, but having to declare that annoying helper variable? I would like to avoid that.
So, what would be a better way to do this? (Better as in fewer lines of code (possibly one-liner), or not declaring a local variable.)
I came up with this:
(function ( t ) { a = b; b = t; })( a ); // swap a and b
Live demo: http://jsfiddle.net/J9T22/
So, what can you come up with?
Upvotes: 2
Views: 2078
Reputation: 11
I assume in the real world one would want this swap to be conditional.
[a,b] = c? [a,b] : [b,a]
You could also replace all instances of a with [a,b][+c] and all b's with [b,a][+c] like:
arr.sort( (a,b) => [a,b][+c] - [b,a][+c] )
or just have a function to call the function:
swapMyFunction = (a,b) => myFunction(b,a)
Upvotes: 0
Reputation: 76736
This is a fun little exercise.
You could do this: a=[b][b=a,0]
var a='a';
var b='b';
a=[b][b=a,0];
alert(a + ', ' + b); // "b, a"
Also +1 from me, ignore the haters ;)
...Oh wait! Is this not a fun little exercise, but actually for real-world use? Then you'd better not do it this way, because it's less readable than var t=a;a=b;b=t!
a=[b][b=a,0]; // wth?
var t=a; a=b; b=t; // ahhh so readable!
But no, seriously, doing it this way actually gives you neat benefits over having to create another variable, because you can do it in line. Var declarations can't usually be part of normal statements, so attempting to do something like (var t=a; a=b; b=t)
will just throw a SyntaxError, but (a=[b][b=a,0])
evaluates to a
, which could be useful.
It's interesting to discuss things like this because, while doing things in unconventional ways may not be welcome in our production code, it is a great way to learn about the language. And that (I think) is what SO is all about. I rest my case.
Upvotes: 8
Reputation: 5298
I slightly disagree with other people, it can be useful. However, defining it inline is bad, bad, bad, bad, bad. If you are going to do it, it should be a higher order function:
function flip(fn) {
return function(a, b) {
return fn.call(null, b, a);
};
}
For example:
function log() {
console.log.apply(console, arguments);
}
flip(log)(1, 2); // 2 1
Now this might seem silly, but this kind of stuff happens quite often when you're mapping/reducing/iterating etc. Say you have some function:
function doSomeStuff(index, value) {
// complex stuff happening here
}
And an array:
var arr = ["foo", "bar", "etc"];
If you were to use, for example, map on this array and needed to call doSomeStuff
you'd have to hand roll this function:
arr.map(function(value, index) {
return doSomeStuff(index, value);
});
Whilst you could say this isn't bad, it is distracting from what you're trying to do (just call the damn function!). With this higher order function it can be reduced to:
arr.map(flip(doSomeStuff));
If you wanted a more complete flip function you could:
function flip(fn) {
return function() {
var args = Array.prototype.slice.call(arguments);
return fn.apply(null, args.reverse());
};
}
And now:
flip(log)(1,2,3,4,5); // 5 4 3 2 1
Upvotes: 0
Reputation: 318488
Using a function for it? Seriously?
The easiest is often the best:
var t = a;
a = b;
b = t;
If you use it e.g. for server-side JS (i.e. you only need to support one JavaScript engine) you might also be able to use the destructuring assignment syntax:
[a, b] = [b, a]
Upvotes: 14
Reputation: 104760
a=[a,b];
b=a[0];
a=a[1];
this uses only the variables a and b, but it creates an array, which is more significant than a temporary variable.
Use the temporary variable.
var t=a; a=b; b=t;
Another upvote for sanity.
Upvotes: 0
Reputation: 150020
What's a better way to swap two argument values?
There is no "better" way, only a number of progressively more obscure and confusing ways.
Some people might view those other methods as "clever", and I guess some of them are, but I wouldn't want to work with anybody who thinks they're actually "better" because I would not want to see such methods cropping up in real project code.
The "clever" maths methods only work if you assume integer values, so in my opinion they're wrong since you didn't specify types.
If you find the three statements ugly you could do this:
var t;
t = a, a = b, b = t;
Yes it's virtually the same thing, but at least it puts the swap code all on the same line.
(Having said all that, I think [a, b] = [b, a];
would be "better" if not for the lack of browser support for it.)
Upvotes: 1
Reputation: 28349
I've read that you should never do this but...
a=5;
b = 7
//add parenthesis to make this do what it should in one line
a ^= b;
b ^= a;
a ^= b;
They should now have each other's values. [edit] as per pointedears' description this doesn't work as stated, but here's the description of how it DOES work... however, as already stated (by others) stick to what's simplest. there's no reason to do this, you will NOT notice any performance gains, and your code will simply become less readable.
http://en.wikipedia.org/wiki/XOR_swap_algorithm
and here it is in action... http://jsfiddle.net/nHdwH/
Upvotes: 3
Reputation: 11327
If you're allowing for Mozilla only, or future ES6 stuff, you can use destructuring assignment:
[a,b] = [b,a]
If the biggest concern is variable environment pollution, you could borrow the arguments
object.
arguments[arguments.length] = a;
a = b;
b = arguments[arguments.length];
But this gets a bit long.
Or you could assign an object to an existing parameter:
a = {a:a,b:b};
b = a.a;
a = a.b;
function foo( a, b ) {
a = {a:a,b:b};
b = a.a;
a = a.b;
console.log(a,b); 'baz' 'bar'
}
foo('bar','baz');
Or eliminate a like like this:
a = {b:b,a:(b=a)};
a = a.b;
Or down to one line:
a = {b:b,a:(b=a)}.b;
Currently in "strict mode" supported implementations, you can do this (if you're actually running in "strict mode"):
a = b; b = arguments[0];
This is because changes to formal parameters has no effect on the arguments
object, and vice versa.
Upvotes: 3
Reputation: 46050
If the values are integers, then you can use arithmetic to do the work:
function foo( a, b ) {
a = -(b = (a += b) - b) + a;
console.log(a);
console.log(b);
}
foo(1,2);
See http://www.greywyvern.com/?post=265
Upvotes: 0