I am revising JavaScript and came to following ES6 example.
let a = 8, b = 6;
// change code below this line
[a,b] = [b,a];
// change code above this line
console.log(a); // a is 6
console.log(b); // b is 8
Not able to figure out how this is working, as we have assignment operator with both side arrays.
Destructuring basically separates an array or an object into separate variables. That is what happens on the left side. Exemple:
var foo = [1, 2]
var [a, b] = foo; // creates new variables a and b with values from the array foo
console.log(a); // prints "1"
console.log(b); // prints "2"
On the right side, you are creating an array with the values [b, a] which will be destructured. As a result, the two variables are switched.
Related
This question already has answers here:
Why is a semicolon needed here? [duplicate]
(1 answer)
Interesting error based on automatic semicolon insertion JS rules. Explanation required
(2 answers)
Use of semicolons in ES6 [duplicate]
(1 answer)
Closed 2 years ago.
Such as 2[a], whose value is undefined.
The code bellow will get an error Cannot access 'b' before initialization
let a = 1, b = 2
[a, b] = [b, a];
I know it caused by the missing semicolon after the b = 2. And after the semicolon has been added
let a = 1, b = 2;
[a, b] = [b, a];
It works fine. Is it caused by the square bracket after the number? If so, what is the meaning of it in javascript?
Is it caused by the square bracket after the number?
Yes.
If so, what is the meaning of it in javascript?
It's a property access operation, just like:
const array = [1, 2, 3];
const b = array[1];
// ^^^−−−−−−−−−−−−−−−−−−−−−−−−−
console.log(b); // 2
You can do property access operations on primitives, and in fact you often do. For instance, on a string primitive:
console.log("hi".toUpperCase()); // "HI"
// or
const fiftyFifty = Math.random() < 0.5;
const method = fiftyFifty ? "toUpperCase" : "toLowerCase";
console.log("Hi"[method]()); // "hi" or "HI"
Or using a number primitive:
console.log(2["toString"]()); // "2"
const n = 2;
console.log(n.toString()); // "2"
console.log(2..toString()); // "2"
When you do, the relevant prototype is used (String.prototype, Number.prototype, etc.) and in loose mode in some situations a temporary object is created (e.g., new String("hi") or new Number(2)).
I have an object named result which is composed of two objects like :
const a = {bar: {baz: 2}};
var b = {foo: 1};
var result = Object.assign({}, a, b);
console.log(result, a, b);
// result -> {bar: {baz: 2}, foo: 1}
// a -> {bar: {baz: 2}}
// b -> {foo: 1}
Now, I am changing the bar property of the result object like:
result.bar.baz = 3;
result.foo = 4;
console.log(result, a, b);
// result -> {bar: {baz: 3}, foo: 4}
// a -> {bar: {baz: 3}} intresting part
// b -> {foo: 1} intresting, too!
(You can copy and paste code to javascript console in order to see the result for both cases by the way)
There are two weird things here. First one is that I am changing the resulting object's property, but constant object a's property changes, too. Even if first one is the case with Object.assign function, how can I change the constant variable? Let's say this is the case despite const variable mutation, then why the change in property foo does not reflect to the object b?
I came with that because I generally use Object.assign to copy objects, but this is pretty weird issue with that function I guess. Any ideas about the case? Thank you.
Declaring a variable with const only prevents it from being changed to another value. It doesn't prevent the data referenced by that value to change.
const foo = {prop: 'bar'};
foo.prop = 'baz'; // Works well
foo = 'baz'; // TypeError: invalid assignment to const `foo'
If you want to prevent an object from being changed, you can freeze it.
Object.freeze(foo);
foo.prop = 'buz'; // TypeError: "prop" is read-only
However, that will only affect own properties. If the value of one of these is another object, it won't become frozen.
This is what happens with Object.assign too. It only copies own properties, and if their value is an object, it won't "clone" it. That is, the references will still be the same, and changes will be reflected.
If you want to deeply clone an object, see What is the most efficient way to clone an object?
Object.assign will work but with the added gotcha that if any of the properties you are assigning from contain an object as a value it does not create a copy of that object, so the references do not change, the property in the created object will point to that same nested object.
Also constant in javascript can be deceiving, you can add and remove properties from a 'const' object as long as you don't try to reassign it to a new object or a different primitive.
Same will occur with arrays, you can create a 'const' array but push pop off of it.
https://jsfiddle.net/eu9yg37s/6/ just something I was messing around in to attempt to display what I mean.
const a = {bar: {baz: 2}};
var b = {foo: 1};
// Example of customizer function that may take into account nested objects and properly copy them using lodash 4.x
var customizer = function(objValue, srcValue) {
if (typeof srcValue === 'object' && typeof srcValue !== null) {
return _.assignWith({}, srcValue, customizer);
}
return _.isUndefined(objValue) ? srcValue : objValue;
}
// This calls assign, but will invoke the customizer function
var result = _.assignWith({}, a, b, customizer);
result.bar.baz = 3;
result.foo = 4;
console.log(result, a, b);
// 'Constant' Array Example
const hi = [true, false, 'hi'];
hi[2] = 23;
console.log('hi.pop', hi.pop());
console.log('hi', hi);
// These will error, uncomment out to see it errors on any of these attempts
//hi = 3;
//hi = 'no';
hi = [true, false, 23];
//hi = false;
//hi = {};
The change doesn't reflect in b, because it wasn't a nested object during the assign operation so the property foo in our created object is pointing to a new primitive 1
I know it's possible in JavaScript to swap two integer values with the XOR option, thus eliminating the need of a temporary variable:
a = 14; b = 27; a^=b; b^=a; a^=b;
// a == 27 and b == 14
But is there a similar no-temp technique in JavaScript for swapping strings?
Alternative swapping methods
ES6 only
ES6's new destructuring assignment syntax:
[a, b] = [b, a]
ES5 compatible
There is an universal single line swapping method that doesn't involve creating new temp variables, and uses only an "on-the-fly" array, here it is:
var a = "world", b = "hello";
b = [a, a = b][0];
console.log(a, b); // Hello world
Explanation:
a=b assigns the old value of b to a and yelds it, therefore [a, a=b] will be [a, b]
the [0] operator yelds the first element of the array, which is a, so now b = [a,b][0] turns into b = a
Then, for strings only, you can also do this:
var a = "world", b = "hello";
a = b + (b = a, "");
console.log(a, b); // Hello world
You can replace the "" with a 0 if you want to do this with numbers.
Explanation:
(b = a, "") assigns the old value of a to b and yelds an empty string
now you have a = b + "", and since that b + "" === b, the old value of b is assigned to a
Performance benchmarks
At this page you can find and run a benchmark of different swapping methods. The result of course varies between browser and JS engine versions.
Here comes a ES6 solution
We can do the Destructuring Assignment and swap like a boss.
var a = "Hello", b = "World!";
console.log(a, b); // Hello World!
[a, b] = [b, a]; //
console.log(a, b); // World! Hello
We can use string replace() method to achieve this!
By using regular expression: "/(\w+)\s(\w+)/"
const name = "Akash Barsagadey";
const swapName = name.replace(/(\w+)\s(\w+)/, "$2 $1");
console.log(swapName); //Barsagadey Akash
This question already has answers here:
How does [b][b = a,0] swap between a and b?
(2 answers)
Closed 9 years ago.
I do not know how to learn demo 2,because it's difficult for me.
//demo1.js
var a = 1;
var b = 2;
var c;
c = b;
b = a;
a = c;
log(a); // a = 2
log(b); // b = 1 I can read this one.
//demo 2.js
var a = 1, b = 2;
a = [b][b = a, 0]; // why? '0' is a varible?
console.log(a,b) //output a = 2, b =1
// v---- 1. v---- 3.
a = [b][b = a, 0];
// ^---^-- 2.
Put the value of the b variable in a new Array.
The next set of square brackets is the member operator used for getting the index. In this case, that space is being used to reassign the value of the a variable to the b variable. This can be done because the original value of b is safely in the Array (from step 1.).
Separated by comma operator, the 0 index is then used as the actual value of the Array being retrieved, which if you'll recall is the original b value. This is then assigned to a via the first = assignment on the line.
So to summarize, b is put in the Array, and is retrieved via the 0 index and assigned to a on the left, but not before a is assigned to b (borrowing the space of the [] member operator).
This could also be written like this:
a = [b, b = a][0];
Only difference now is that the second index of the Array is used to do the assignment. Probably a little clearer like this.
The comma operator in Javascript evaluates its left operand, throws it away and returns its right operand after evaluating. Its only use is when the left operand has a side-effect (like modifying a variable's value) but you don't want its result.
[b] defines an array containing b.
[b = a, 0] evaluates b = a - so b now contains the value of a. Then it throws it away. Then it takes the element at index 0 of [b] - returning b. a now contains the value of b that was stored there, rather than the up-to-date value of b, so our swap is successful (albeit obfuscated).
I've made an experiment in JavaScript:
var x=[ "1","2","3","4","5","6"];
c=(b = x)[2] ; //<--- what is this syntax?
alert(b ); // 1,2,3,4,5,6
alert(c ); // 3
I figured it out how it works. It saves me a line of equalization. Still, I was wondering about this strange syntax. How is it called and where can I read about it?
= operator returns a value being assigned so (b = x) returns value of x. That results in x[2] being assigned to c.
(note: "returns x" changed to "returns value of x" according to comments)
See below
b=x assigning the data of x to b and hence you are getting alert as 1,2,3,4,5,6
c=(b=x)[2] is displaying the second content of array i.e. 3.
Below is how c=(b=x)[2] works
c=(b=x)[2]
b=x
c=b[2]
let me know if you need further details...
this happens because of an assigment operator returns value in java script.
Think about it like this:
You make an assignment:
b = x;
Now in object oriented terms, its like invoking a method = on b with an x as an argument
b.=(x)
Here the '=' is like a method name
Now if its the method, why it can't return a value (its return type is other than void)?
Here you can find some additional explanation about this:
Link1
Link2
Hope this helps
var x = ["1","2","3","4","5","6"];
c=(b = x)[2]; // b = x; -> shallow copy of the array
// b -> now hods the array of x
// b[2] -> get the second element of the array
alert(b ); // b is pointing to the array
alert(c ); // c has the 3-rd element (array counting is from 0 - 0,1,2)
b.push("7"); // we add a new item to the array
alert(b); // 1,2,3,4,5,6
alert(x); //1,2,3,4,5,6,7 !
The same code can be written as:
var x = b = ["1","2","3","4","5","6"], c = b[2];
console.log(b); //=> 1,2,3,4,5,6
console.log(c); //=> 3
Or even:
var c = (x = b = ["1","2","3","4","5","6"])[2];
console.log(b); //=> 1,2,3,4,5,6
console.log(c); //=> 3
In var c = (b=x)[2], the parentheses force b=x to execute first. In both cases anyhow, when for example used within a function scope, the statement would create variable b in the global scope, so I would consider it bad practice.