Swapping terms using Assignment de-structuring wont work inside a function - javascript

let a = 'alpha', b = 'beta';
[a,b] = [b,a];
This swaps the values of a and b as intended;
but when placed inside a function it doesn't work
let c = 'charlie', d = 'delta';
swapVar = (x,y) => [x,y] = [y,x]
swapVar(c,d);
What am I missing here?

When you do
let a = 'alpha', b = 'beta';
[a,b] = [b,a];
You're swapping the values of a and b.
When you do
let c = 'charlie', d = 'delta';
swapVar = (x,y) => {
// x and y are separate variables scoped within this block
[x,y] = [y,x]
console.log(x,y); // it is swapped alright but isn't reflected on c and d
c = x;
d = y;
// Now the value will have been reflected.
}
swapVar(c,d);
So, within the function the values are swapped but aren't reflected outside. You could modify the program like this:
swapVar = (x,y) => [y,x]
[c, d] = swapVar(c, d); // now you're reflecting the swapped values on the outside
To have the intended effect.

You are doing the swap in a scope where the variables aren't being "exported".
In the first example, you act on the actual variables a and b in the scope they are defined in.
However, in the second example, you are acting on the variables x and y which are the same value as c and d but aren't the actual c and d since they are primitives so the c and d outside the scope of the arrow function is not affected.
{
let a = 'alpha',
b = 'beta';
console.log("Test 1");
console.log(`before a: ${a} b: ${b}`);
[a, b] = [b, a];
console.log(`after a: ${a} b: ${b}`);
}
{
let c = 'charlie',
d = 'delta';
console.log("Test 2");
console.log(`before c: ${c} d: ${d}`);
swapVar = (x, y) => [x, y] = [y, x]
/*
function swapVarExpanded(x, y) {
const tmp = [y, x];
x = tmp[0];
y = tmp[1];
// Doesn't actually matter
// because x and y die at the next closing curly brace due to scope
}
*/
swapVar(c, d);
console.log(`after c: ${c} d: ${d}`);
}

Related

Why can't I swap 2 variables in JavaScript?

I am trying to swap two variables in JavaScript, but my code does not work. Can anyone tell me why?
This should return 10, 5 I think, because I already called the swap function. But instead, it returns 5, 10.
function swap(a, b) {
var temp = a;
a = b;
b = temp
}
var x = 5;
var y = 10;
swap(x, y);
console.log(x, y);
JavaScript, like Java, is pass by reference only. This means that while your function does swap the values, the actual values of x and y in the calling scope have not been swapped. One workaround here might be to return an array of values, swapped:
function swap(a, b) {
return [b, a];
}
var x = 5;
var y = 10;
[x, y] = swap(x, y);
console.log("x after swap = " + x);
console.log("y after swap = " + y);
Note that here the critical line is the assignment:
[x, y] = swap(x, y);
This reassigns x and y to the swapped array in one line.
You can use Destructuring assignment method:
let a = 1;
let b = 2;
[a, b] = [b, a];
a; // => 2
b; // => 1
Javascript function values aren't passed by reference, instead values get copied in a,b. So instead return values:
function swap(a, b) {
return [b, a];
}
Later get it:
[x, y] = swap(x, y);
You can achieve this using JavaScript's objects, which passed by sharing, similar to pass by reference you may have experienced in other languages. This allows you to do a few things that are not possible with primtive values -
function ref (value) {
return { value }
}
function deref (t) {
return t.value
}
function set (t, value) {
t.value = value
}
function swap (a, b) {
const temp = deref(a)
set(a, deref(b))
set(b, temp)
}
const x = ref(3)
const y = ref(5)
swap(x,y)
console.log(deref(x), deref(y)) // 5 3
You can make this abstraction in any way you choose -
const box = v => [v]
const unbox = t => t[0]
const set = (t, v) => t[0] = v
function swap (a, b) {
const temp = unbox(a)
set(a, unbox(b))
set(b, temp)
}
const x = box(3)
const y = box(5)
swap(x,y)
console.log(unbox(x), unbox(y)) // 5 3

Save reference to a function with parameters in JavaScript

I am calling a function at several places within my app. This function takes several parameters whose values might change. To avoid re-typing, I want to save a reference to this function so that I can simply call this referred function everywhere. Here is the simplified code:
const func1 = (a,b,c) => a + b + c;
let a = 1, b = 2, c = 3;
const func2 = func1.bind(this, a, b, c);
func2();
//prints 6
c = 6;
func2();
//still prints 6!
How can I ge func1 to be executed with updated values of a, b and c by calling func2?
Use arrow function:
const func1 = (a,b,c) => a + b + c;
let a = 1, b = 2, c = 3;
const func2 = () => func1(a, b, c);
console.log(func2());
c = 6;
console.log(func2());
You can bind the function to an array of [a, b, c] instead, and then change the property at index 2:
const func1 = (a,b,c) => a + b + c;
const params = [1, 2, 3];
const func2 = () => func1(...params);
func2();
params[2] = 6;
func2();
If you only change c, you could consider binding the function to a and b, and then passing the changing c:
const func1 = (a,b,c) => a + b + c;
const params = [1, 2];
const func2 = (c) => func1(...params, c);
func2(3);
func2(6);
If you want to use params from scope where you declare your function, just skip those params in function signature
const f = () => a + b + c;
let a = 1, b = 2, c = 3;
console.log(f());
c = 6;
console.log(f());
Instead of this const func2 = func1.bind(this, a, b, c);
You can use this function(arrow): const func2 = () => func1(a, b, c);

Passing a specific pre-defined parameter to a function

Let it be so :
let something = (a , b , c = 0 , d = 0 , e = 0) =>
{console.log(`a is ${a}; b is ${b};c is ${c};d is ${d};e is ${e}`)};`
If I give more then two params to a function, it takes them as respectively.
What if I want to pass the value to "e" variable and skip others, that are predefined?
You can make the params an object.There are two benefits to it, first, you don't have to worry about the order and you won't have to pass a value to c or d.
let something = ({a , b , c = 0 , d = 0 , e = 0}) => {
return `a is ${a}; b is ${b};c is ${c};d is ${d};e is ${e}`;
}
console.log(something({a: 12 , b: 13, e: 51})); //"a is 12; b is 13;c is 0;d is 0;e is 51"
Just pass undefined:
let something = (a, b, c = 0, d = 0, e = 0) => {
console.log(`a is ${a}; b is ${b}; c is ${c}; d is ${d}; e is ${e}`);
};
something(1, 2, undefined, undefined, 3);
You can also wrap the optional parameters in a single argument which will be destructured:
let something = (a, b, {c=0, d=0, e=0} = {}) => {
console.log(`a is ${a}; b is ${b}; c is ${c}; d is ${d}; e is ${e}`);
};
something(1, 2);
something(1, 2, {c: 3});
something(1, 2, {e: 3});

How to swap two variables in JavaScript

I have this two variables:
var a = 1,
b = 2;
My question is how to swap them? Only this variables, not any objects.
Here's a one-liner to swap the values of two variables.
Given variables a and b:
b = [a, a = b][0];
Demonstration below:
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>
ES6 (Firefox and Chrome already support it (Destructuring Assignment
Array Matching)):
let a = 5, b = 6;
[a, b] = [b, a];
console.log(`${a} ${b}`);
You can do this:
var a = 1,
b = 2,
tmp;
tmp = a;
a = b;
b = tmp;
For readability and maintainability, this can't be beat (at least in JavaScript). Anybody maintaining the code (including you six months from now) will know exactly what's going on.
Since these are integers, you can also use any number of clever tricks1 to swap without using a third variable. For instance you can use the bitwise xor operator:
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);
This is called the XOR swap algorithm. Its theory of operation is described in this Wikipedia article.
1"The competent programmer is fully aware of the limited size of his own skull. He therefore approaches his task with full humility, and avoids clever tricks like the plague." — Edsger W. Dijkstra
Don't use the code below. It is not the recommended way to swap the values of two variables (simply use a temporary variable for that). It just shows a JavaScript trick.
This solution uses no temporary variables, no arrays, only one addition, and it's fast.
In fact, it is sometimes faster than a temporary variable on several platforms.
It works for all numbers, never overflows, and handles edge-cases such as Infinity and NaN.
a = b + (b=a, 0)
It works in two steps:
(b=a, 0) sets b to the old value of a and yields 0
a = b + 0 sets a to the old value of b
Since ES6, you can also swap variables more elegantly:
var a = 1,
b = 2;
[a, b] = [b, a];
console.log('a:', a, 'b:', b); // a: 2 b: 1
You can now finally do:
let a = 5;
let b = 10;
[a, b] = [b, a]; // ES6
console.log(a, b);
Here's a one-liner, assuming a and b exist already and have values needing to be swapped:
var c=a, a=b, b=c;
As #Kay mentioned, this actually performs better than the array way (almost 2x as fast).
You could use a temporary swap variable or XOR.
a = a ^ b
b = a ^ b
a = a ^ b
This is just a basic logical concept and works in every language that supports XOR operation.
edit: see the Comments. Forgot to tell that this works for sure only with integer. Assumed the integer variables from question's thread
Use a third variable like this:
var a = 1,
b = 2,
c = a;
a = b; // must be first or a and b end up being both 1
b = c;
DEMO - Using a third variable
As your question was precious "Only this variables, not any objects. ", the answer will be also precious:
var a = 1,
b = 2
a=a+b;
b=a-b;
a=a-b;
it's a trick
And as Rodrigo Assis said, it "can be shorter "
b=a+(a=b)-b;
Demo:
http://jsfiddle.net/abdennour/2jJQ2/
ES6 Destructuring:
Using an array: [a, b] = [b, a]; // my favorite
Using an object: {a, b} = {a:b, b:a}; // not bad neither
How could we miss these classic oneliners
var a = 1, b = 2
a = ({a:b, _:(b=a)}).a;
And
var a = 1, b = 2
a = (_=b,b=a,_);
The last one exposes global variable '_' but that should not matter as typical javascript convention is to use it as 'dont care' variable.
I see kind of programming olympiad here. One more tricky one-line solution:
b = (function(){ a=b; return arguments[0]; })(a);
Fiddle: http://jsfiddle.net/cherniv/4q226/
Single line swapping
a = a^b^(b^=(a^b));
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);
remove or comment the 2 //or's and run with the one set of code
http://jsfiddle.net/USdv8/57/
We are able to swap var like this :
var val1 = 117,
val2 = 327;
val2 = val1-val2;
console.log(val2);
val1 = val1-val2;
console.log(val1);
val2 = val1+val2;
console.log(val2);
first way,
var a = 5, b = 9;
a = a - b;
b = a + b;
a = b - a;
console.log(a, b);
second way
var a = 19, b = 22;
[a, b] = [b, a];
console.log(a, b);
simple and clear answer.
Because I hear this method runs slower:
b = [a, a = b][0];
If you plan on storing your vars in an object (or array), this function should work:
function swapVars(obj, var1, var2){
let temp = obj[var1];
obj[var1] = obj[var2];
obj[var2] = temp;
}
Usage:
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'}
We can use the IIFE to swap two value without extra parameter
var a = 5, b =8;
b = (function(a){
return a
}(a, a=b));
document.write("a: " + a+ " b: "+ b);
Till ES5, to swap two numbers, you have to create a temp variable and then swap it.
But in ES6, its very easy to swap two numbers using array destructuring. See example.
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
Know more about JavaScript ES6 destructuring
Although the same answer is given previously, but here is a png to describe it.
Simplest form possible:
let a = 2, b = 4;
[b, a] = [a, b];
a more verbose approach would be
let a = 2, b = 4;
a = [a, b];
b = a[0];
a = a[1];

Why does this work? Object references in Javascript

I've finally been curious enough to find out why javascript does its voodoo magic to learn why not all object references are created equal.
Given the example:
var a, b, c, d;
a = 100; b = a;
c = {}; d = c;
b = 10; d.e = 'f';
console.log(a, b); // outputs 100, 10
console.log(c, d); // outputs object => e = 'f', object => e = 'f'
If all variables in javascript are objects, then what makes the use case with c and d cast explicitly as an Object so different than defining a and b as Number? Or, why will c and d be linked to one another, and not a and b?
All variables in JavaScript are not objects. There are native types as well.
c and d are not linked to one another. They are pointing to the same object reference. If you were to reassign d to something else, it will not affect c.
var c = {};
var d = c;
d = { foo: "bar" };
c === d // false
However, if you were to modify the object being referenced by c or d, it will modify the same object since c and d are both referring to the same object as in your example.
It looks to me that the difference is with b, you're reassigning the variable to a new object/value, while with d, you're modifying the existing object.
The value of a that is assigned to b is a Number. The value assigned from c to d is a reference to an Object.
var a, b, c, d;
a = 100; // a has value 100, a number
b = a; // b has value 100, a number
c = {}; // c has value p, a reference to some object P
d = c; // d has value p, a reference to P
b = 10; // b has value 10, a number
d.e = 'f'; // P.e has value 'f', a string

Categories