Is Babel's implementation of ES6 object destructuring correct? - javascript

So basic desctucturing is fine, {a, b} = obj transpiles to a = obj.a; b = obj.b.
My question is around a bit of an odd syntax that I accidentally ran across and I'm wondering if someone can point me at spec since I can't find it:
({a, b} = obj).c
That does the two a, b assignments and then returns obj.c. It's actually quite useful to me for a byte stream decoder, as I can write:
let width = ({bytes} = intDecode(bytes)).number;
My issue is that I haven't seen this syntax anywhere and don't want to rely on something that is either incorrectly implemented or in proposal stage.

There is nothing special in Destructuring Assignment: it's evaluated as any other Assignment with = operator.
So it returns rval.
Which means you can rely on your syntax.
Some details:
The Destructuring Part is evaluated in the 6[1]:
Let status be the result of performing DestructuringAssignmentEvaluation of assignmentPattern using rval as the argument.
and after this item the assignment evaluation happens as usually, like in the a = b = 42; case.
References:
12.14.4 Assignment Operators / Runtime Semantics: Evaluation
12.14.5.2 Destructuring Assignment / Runtime Semantics: DestructuringAssignmentEvaluation

Yes, it is expected to work like this (see #zerkms' answer for details). That you haven't seen the syntax anywhere is because it's not exactly good practice to access properties on the result of an assignment expression, as it makes the code quite unreadable. Whether you assign to a normal variable or a destructuring expression doesn't make much difference here.
However, you could quite easily transform the code into a reasonable destructuring assignment:
let {bytes, number:width} = intDecode(bytes);
or actually, more closely to your original code:
let width;
({bytes, number:width} = intDecode(bytes));

Related

Is there a difference between returning a value and returning an expression in JavaScript?

A friend of mine just asked me which of the following two expressions would be the better choice. While I understand the question, and thus the definition of better, is potentially a matter of opinion and thus off-topic; I was keen to understand if there was a good reasoning in favour of one.
var count = _.reduce(randomData, function(prefix, businessData){
return prefix + businessData.length;
}, 0);
return {
name: randomName,
pos: position[randomName],
count: count
};
or
return {
name: randomName,
pos: position[randomName],
count:
_.reduce(randomData, function(prefix, businessData){
return prefix + businessData.length;
}, 0)
};
Both another colleague and I were in agreement that the first one would be better as it's clearer, potentially easier to debug and more easily understood but outside of that we couldn't justify our choice.
Is there a reason why one would favour returning the value against returning the expression?
Is there a difference between returning a value and returning an expression in JavaScript?
No, you're returning a value either way. More accurately, from your code examples, you're assigning a value to the count property of the object you're returning a reference to either way.
The only difference in your code examples is when reduce is called. In the first one, it's called before the construction of the object you're returning begins. In the second, it's called during that construction. There's no difference in what the function then goes on to return, though.
Is there a reason why one would favour returning the value against returning the expression?
Since the first answer above is "no," the only reasons take us into, or at least very near, the land of opinion.
The closest objective measure I can come up with is one of the ones you pointed out: Debugging. With the first one, you can easily see count before constructing and returning the object. With the second, that's more difficult.
More detail about this object construction thing, in case that was a surprise: JavaScript defines the order that the property initializers in an object initializer are run: Unsurprisingly, they're run in source-code order. So for instance, if we have this code:
var num = 0;
function foo() {
return ++num;
}
var obj = {
a: foo(),
b: foo(),
c: foo()
};
...we know for certain that the value of obj.a is 1, obj.b is 2, and obj.c is 3. That's defined by the specification.

JSHint -Expected a conditional expression and instead saw an assignment

I am well aware of similar questions, but I still can't solve mine basing on those.
So, my code looks like this:
for (var e, i = 0; e = formErrors[i]; i += 1)
JSHint returns said error in char 39, so with ; after formErrors[i]. What can I do?
JSHint is warning you of a potential bug. It is expected that the 2nd part of a for statement will be a Boolean expression. Normally, you'd use one of the comparison operators for this (==, ===, !=, > etc..). Since the expression is e = formErrors[i] it looks like it might be a mistake, possibly due to a missing equal sign. This is a common typo that causes a lot of bugs.
Apparently, in this case it is not a bug, but rather an intentional usage of the fact that any expression evaluates to something, and an assignment expression evaluates to the assigned value:
var x;
alert(x = 1);
So the for statement actually assigns a new value to e, but also evaluates that value as a condition, casting it to Boolean if required.
You could refactor your code such that it both assigns the value and uses a casting operation that would satisfy JSHint and make the code a bit more obvious to the reader:
for (var e, i = 0; !!(e = formErrors[i]); i += 1)
The 2nd ! (the one directly in front of (e...) causes a casting to Boolean, but also negates it, the 1st ! reverts this negation.
That's just a very weird way of writing a loop. JsHint expects a boolean expression ("conditional") there, and judges that your assignment is a mistake and you actually wanted a comparison (== instead of =).
What you should do is switch to the following common array iteration idiom:
for (var i = 0; i < formErrors.length; i += 1) {
var e = formErrors[i];
…
(Which works the same as your original code for non-sparse formErrors arrays that contain no falsy values.)
Or alternatively, if you want to write non-idiomatic code, dump jshint :-)
e = formErrors[i] is an assignment, don't you want a condition there? use a comma after i=0 in that case, else put a condition after the semicolon.
Typically, the middle element in a for loop is the condition that is used to decide whether to continue the loop or not. You have an assignment there, if you wanted a condition you should use e === formErrors[i] (or with a double =, but that is usually not recommended).
An assignment can technically work, because e can be, for example, some object (true) or null (false). But that is considered bad coding style, usually, and won't make for very readable code.

Array Notation Order of Operations

I have written the following code
o[s += "a"] = o[s += "b"] = o[s += "c"] = 0;
I was curious as to why the variable s ends up storing "abc" and not "cba". It seems like it would be easier for the the code to execute from right to left.
I seems as though the executor chooses and index for storage then decides what goes in there, but doing this make it sound slower since there would be so many states and memory being pushed onto the stack. Can somebody explain as to why it makes sense for the code to execute in the order that is does?
I have included a fiddle with a few more examples. http://jsfiddle.net/eggrdtuk/3/
Luke's comment is right. We can look at the MDN page for operator precedence.
Computed Member Access has precedence 1 and Assignment has precedence 16. So the property access expressions are evaluated first, then the assignment operations. Furthermore, Computed Member Access has left-to-right associativity, while Assignment has right-to-left associativity.
So, we can think of the first step as parsing the property access expressions from left-to-right:
o["a"] = o["ab"] = o["abc"] = 0
and the second step as doing assigments from right-to-left:
(o["a"] = (o["ab"] = (o["abc"] = 0)))
(o["a"] = (o["ab"] = 0))
(o["a"] = 0)
I don't see how changing associativity for either step would change the performance. But if there is a reason, I would love to learn :)

Ruby's ||= (or equals) in JavaScript?

I love Ruby's ||= mechanism. If a variable doesn't exist or is nil, then create it and set it equal to something:
amount # is nil
amount ||= 0 # is 0
amount ||= 5 # is 0
I need to do something similar in JavaScript now. What's the convention or proper way to do this? I know ||= is not valid syntax. 2 obvious ways to handle it are:
window.myLib = window.myLib || {};
// or
if (!window.myLib)
window.myLib = {};
Both are absolutely correct, but if you are looking for something that works like ||= in ruby. The first method which is variable = variable || {} is the one you are looking for :)
You can use the logical OR operator || which evaluates its right operand if lVal is a falsy value.
Falsy values include e.g null, false, 0, "", undefined, NaN
x = x || 1
The operator you asked about has been proposed as a feature in JavaScript. It is currently at Stage 4, and it will be introduced in the next ECMAScript standard, which is expected to be published in 2021.
You can use it now using the plugin-proposal-logical-assignment-operators Babel plugin. I have never used that plugin, so I have no idea how well it works.
If you're working with objects, you can use destructuring (since ES6) like so:
({ myLib: window.myLib = {} } = window);
...but you don't gain anything over the accepted answer except confusion.
As of 2021, you can use ||= with identical behavior to Ruby as long as you are transpiling or don't care about Opera/IE.
Logical OR assignement, ||= is now supported natively in javascript on all major browsers except Opera and IE. Current caniuse matrix. MDN reference.
Typescript added support for the operator in version 4. If you need to support IE/Opera you can use the babel plugin to transpile for broad compatibility.
Logical nullish assignment (??=)
x ??= 23
Documentation & Browser compatibility
Ruby's ||= operator short circuits assignment. It can be thought of like this:
return a || a = b
So in javascript, this looks very similar:
return a || (a = b);
It seems as pointed out in the comments below however, that this literal ruby form is less efficient than the standard javascript idiom a = a || b.
For reference:
http://www.rubyinside.com/what-rubys-double-pipe-or-equals-really-does-5488.html
You can achieve the desired behaviour using |= operator in javascript for integers only. But you have to define the variable first.
let a = 0
a |= 100
console.log(a) // 100
For objects
let o = {}
o.a |= 100
console.log(o) // {a: 100}
For Arrays
let arr = []
arr[0] |= 100
console.log(arr) // [100]

Javascript: var = var = function

I'm sure this thing is duplicated somewhere but I don't know what to search.
So, I've been looking through a Node.JS Application and found this code and wondered what it does. I have tried searching but I don't know what to search so I was hoping someone would it explain it to me.
init = refresh = function () {
// code here..
};
I understand 1 equals, but why 2? does it make some sort of alias so that function can be run with both init and refresh?
= resolves the right hand side and then assigns the result to the left hand side.
The result of doing this is the same as the result assigned.
So that assigns the function to both init and refresh
Quentin did a very good job telling you what it is doing.
I just wanted to chime in to give an example where you might use this:
Say for instance you have an object:
var obj = {
init: function() {
var x = this.x = [1,2,3];
}
};
What this allows you to do is reference your x variable two different ways (either through x or this.x).
Now why would you do this?
Well two major reasons.
It is faster to access x rather than this.x (but you still need to access it elsewhere)
It produces easier to read code when having to read/write to x lots of times in one function.
This is just another reason why you would use it.
But in most cases it is just aliases, such as: forEach -> each
Here's an explanation using operator associativity and precedence.
So, looking at an operator precedence description from Mozilla, when an expression includes multiple operators of the same precedence, as in
a OP b OP c
, then you check whether that level of precedence uses right-to-left or left-to-right associativity.
a = b = c
The assignment operator in JavaScript is the only operator on its level of precedence.
It has right-to-left associativity
So in a = b = c, b = c is evaluated first, assigning the value of c to b.
Then the expression becomes a = b.

Categories