ES6 Array destructuring weirdness - javascript

Can anyone explain, why the following happens with ES6 array destructuring?
let a, b, c
[a, b] = ['A', 'B']
[b, c] = ['BB', 'C']
console.log(`a=${a} b=${b} c=${c}`)
// expected: a=A b=BB c=C
// actual: a=BB b=C c=undefined
http://codepen.io/ronkot/pen/WxRqXg?editors=0011

As others have said, you're missing semicolons. But…
Can anyone explain?
There are no semicolons automatically inserted between your lines to separate the "two" statements, because it is valid as a single statement. It is parsed (and evaluated) as
let a = undefined, b = undefined, c = undefined;
[a, b] = (['A', 'B']
[(b, c)] = ['BB', 'C']);
console.log(`a=${a} b=${b} c=${c}`);
wherein
[a, b] = …; is a destructuring assignment as expected
(… = ['BB', 'C']) is an assignment expression assigning the array to the left hand side, and evaluating to the array
['A', 'B'][…] is a property reference on an array literal
(b, c) is using the comma operator, evaluating to c (which is undefined)
If you want to omit semicolons and let them be automatically inserted where ever possible needed, you will need to put one at the start of every line that begins with (, [, /, +, - or `.

You've fallen into a trap of line wrapping and automatic semicolon insertion rules in JavaScript.
Take this example:
let x = [1, 2]
[2, 1]
It's the interpreted as:
let x = [1, 2][2, 1] // === [1, 2][(2, 1)] === [1, 2][1] === 2
That weird [(2, 1)] thing above is related to how Comma Operator works.
Thus, your example:
let a, b, c
[a, b] = ['A', 'B']
[b, c] = ['BB', 'C']
console.log(`a=${a} b=${b} c=${c}`)
Is interpreted as:
let a, b, c
[a, b] = ['A', 'B'][b, c] = ['BB', 'C']
console.log(`a=${a} b=${b} c=${c}`)
Now, if you insert a semicolon, it will work as you intended:
let a, b, c
[a, b] = ['A', 'B']; // note a semicolon here
[b, c] = ['BB', 'C']
console.log(`a=${a} b=${b} c=${c}`)
Also, it's a good idea to check your code by pasting it into Babel repl to see the generated output:
'use strict';
var a = void 0,
b = void 0,
c = void 0;
var _ref = ['A', 'B'][(b, c)] = ['BB', 'C'];
a = _ref[0];
b = _ref[1];
console.log('a=' + a + ' b=' + b + ' c=' + c);

I believe you have forgotten the line breaks ';'. Below is the corrected code. Please try:
let a,b,c
[a, b] = ['A', 'B'];
[b, c] = ['BB', 'C'];
console.log(`a=${a} b=${b} c=${c}`)

let a, b, c
[a, b] = ['A', 'B']***;***
[b, c] = ['BB', 'C']
console.log(`a=${a} b=${b} c=${c}`)
console: a=A b=BB c=C

Related

Group every two items in an array while sharing the endings, like a chain

Assuming I have an array like this: [A, B, C, D, E, F]
, How can I group them like this:
[[A, B], [B, C], [C, D], [D, E], [E, F]]
(Notice how every last element is shared with the next group, but with the opposite index.)
I know this ain't a big deal of a problem, but I'm trying to keep it simple and short, maybe with Array.reduce() if possible:
arr.reduce(function (rows, key, index) {
return (index % 2 == 0 ? rows.push([key])
: rows[rows.length-1].push(key)) && rows;
}, []);
// Output: [[A, B], [C, D], [E, F]]
One liner solution is
arr.map((c, i) => [c, arr[i + 1]]).slice(0, -1)
SOLUTION 1
You can use map and filter here to achieve the result
At current index return an array which will contain current element and next element till last element
const arr = ['A', 'B', 'C', 'D', 'E', 'F'];
const result = arr
.map((c, i) => (i < arr.length - 1 ? [c, arr[i + 1]] : null))
.filter(Boolean);
console.log(result);
SOLUTION 2
You can also acheve this if you get all array combination and remove last one as:
const arr = ['A', 'B', 'C', 'D', 'E', 'F'];
const result = arr.map((c, i) => [c, arr[i + 1]]).slice(0, -1);
console.log(result);
Just with reduce method, you can add the current item and the item after it in an array, and then push this array into the accumulator of the reducer method, and before push you need to check if the current item isn't last item in the array.
const arr = ['A', 'B', 'C', 'D', 'E', 'F']
const result = arr.reduce((acc, item, index) => {
const nextItem = arr[index + 1]
nextItem ?? acc.push([item, nextItem])
return acc
}, [])
console.log(result)
If you don't want to stick to the reduce() approach here's another method using map() and slice().
const data = ['A', 'B', 'C', 'D', 'E', 'F'];
const result = data.map((_, i) => (i < data.length - 1 ? data.slice(i, i + 2) : null)).filter(Boolean);
console.log(result);
The simplest will be a standard for loop. It happens to also be shorter than many of the reduce() answers with no extraneous filters or conditions.
const arr = ['A', 'B', 'C', 'D', 'E', 'F'];
const result = [];
for (let i = 0; i < arr.length - 1; i++) {
result.push([arr[i], arr[i + 1]]);
}
console.log(result);
Alternatively a while loop is actually shorter if a little less transparent.
const arr = ['A', 'B', 'C', 'D', 'E', 'F'];
let result = [], i = 0;
while (i < arr.length - 1) {
result.push([arr[i], arr[++i]]);
}
console.log(result);

Return multiple values from function in an assigment

If I want to return a multiple values from a function, in an assigment, do I need to use an intermediate array to receive those values?
How am I used to do it in JavaScript:
let f = () => return [1, 2, 3];
let a, b, c, arr;
arr = f();
a = arr[0]; b = arr[1]; c = arr[2]
Is JavaScript like C, returning assignment to the first lhand operator, or is it possible to do something more flexible, like in this example from Ruby (without using loop):
def f
return 1, 2, 3
end
a, b, c = f
My motivation is simply lack of readability in the JavaScript method.
Issues
return not needed in simple arrow function
destructure assignment syntax
let f = () => [1, 2, 3];
let [a, b, c] = f();
console.log(a, b, c)
You can get values from an array either using index or using destructuring . If there are multiple values then you can easily destructure and store it in different variables in a single statement.
let f = () => [1, 2, 3];
//Using Destructuring
const [a, b, c] = f();
console.log(a, b, c);
// Accessing using index
const arr = f();
const m = arr[0];
const n = arr[1];
const o = arr[2];
console.log(m, n, o);
Since you are using an array to return multiple values then you can use either implicitly return in a function of you can explicitly return an array from it
1) Explicitly return
let f = () => {
return [1, 2, 3];
};
const [a, b, c] = f();
console.log(a, b, c);
2) Implicitly return
let f = () => [1, 2, 3];
const [a, b, c] = f();
console.log(a, b, c);

Can someone explain what is going on with line 3 // [a, b] = [b, a];

its simple but im a bit lost on what its doing besides swapping the values.
function shorter_reverse_longer(a,b){
if (b.length > a.length)
[a, b] = [b, a];
return b + a.split('').reverse().join('') + b;
}
It creates an array with [b, a] and assigns each value to a, b by destructuring an array. Please refer to this page.

js destructuring assignment not work in while loop

[a,b] = [b, a+b] here not work , a b always 0 and 1.
If use a temp variable to swap the value ,that works.
function fibonacciSequence() {
let [a, b, arr] = [0, 1, []]
while (a <= 255) {
arr.concat(a)
[a, b] = [b, a + b]
console.log(a, b) // always 0 1
}
}
console.log(fibonacciSequence())
The problem is that Automatic Semicolon Insertion isn't doing what you expect. It's not adding a semicolon between
arr.concat(a)
and
[a, b] = [b, a + b]
so it's being treated as if you wrote
arr.concat(a)[a, b] = [b, a + b]
Add all the semicolons explicitly and you get a correct result.
function fibonacciSequence() {
let [a, b, arr] = [0, 1, []];
while (a <= 255) {
arr.concat(a);
[a, b] = [b, a + b];
console.log(a, b); // always 0 1
}
}
console.log(fibonacciSequence())
You can use the below function as well:
function fibonacciSequence() {
let [a, b] = [0, 1];
while (a <= 255) {
b = a + b;
a = b - a;
console.log(a,b);
}
}
fibonacciSequence();

Array destructuring - unexpected behavior

const [a, b] = [1, 2]
// expected to be equal to
// const a = 1
// const b = 2
const [c, d] = [3, 4]
// expected to be equal to
// const c = 3
// const d = 4
[a, b] = [b, a]
// expected Assignment to constant variable error
console.log(a, b, c, d)
// => 1, 2, 2, 1
Can someone explain what is wrong with this code? What happened to variables c and d?
You're not using semi-colons and ASI doesn't always work the way you would like.
Your code is equivalent to this:
const [a, b] = [1, 2];
const [c, d] = [3, 4][a, b] = [b, a];
console.log(a, b, c, d);
[3, 4][a, b] in this case evaluates as [3,4][2] since the second comma is just the comma operator and b === 2. That makes the assignment equivalent to [3,4][2] = [b,a] which results in a temporary array [3,4,[2,1]] being created and the result of the assignment expression [2,1] is then assigned to [c,d].
Try adding semi-colons and you will get the expected results:
const [a, b] = [1, 2];
// expected to be equal to
// const a = 1
// const b = 2
const [c, d] = [3, 4];
// expected to be equal to
// const c = 3
// const d = 4
[a, b] = [b, a];
// expected Assignment to constant variable error
console.log(a, b, c, d);
It's basically a problem with not terminating commands properly with a semi-colon (;). If you add them to the end of each command you will get the proper result.. and also run into the problem where you cannot reassign a and b as they're declared as const.
Instead of:
const [a, b] = [1, 2];
Try:
const a = 1, b = 2;
const c = 3, d = 4;
To swap the values, try something like:
var temp;
temp = a; a = b; b = temp;

Categories