Order of evaluation in if statement in with ES6 destructuring - javascript

I recently stumbled upon the new Destructuring Javascript feature that is available with ES6.
Found out a weird situation where i am not really sure of what is going on. Hopefully you guys will help me understand.
If i type this in my console:
var car={}
var {undefinedProp: es6Magic} = car;
I get an undefined. Looks fair to me, since car has no defined property.
But if i use an If statement around it i get a different and unexpected result:
function testPriorities() {
var car = {}
if ({
undefinedProp: es6Magic
} = car) {
console.log('how do i even get here', es6Magic);
}
}
What the hell?
Why is that es6Magic is assigned with an undefined value and it still returns true?
What rules are being applied when running the if statement?

If i type this in my console:
var car={}
var {undefinedProp: es6Magic} = car;
I get an undefined.
But not because es6Magic has an undefined value (it does, I mean it's not the reason). It's because variable declarations have no result value, and your complete snippet does not have a result (unlike expression statements).
But if i use an If statement around it i get a different and unexpected result:
var car = {}
if ({undefinedProp: es6Magic} = car) {
console.log('how do i even get here', es6Magic);
}
I guess that is true because the car exists, but why does it evaluate differently from the console?
Actually you'll still get the undefined result from the last statement, after the console.log output.
And yes, the if condition evaluates to a truthy value because car exists - that's what assignment expressions always do. This doesn't even have anything to do with destructuring, … = car always evaluates to the right hand side car regardless what the left hand side target expression is.
You can also try
> var car = {}, es6Magic;
undefined
> ({undefinedProp: es6Magic} = car); // no `var` - plain assignment!
[object Object]

The console shows undefined because a variable declaration doesn't return anything, it declares a variable.
The second version works because {foo: bar} is interpreted as an object literal, which you are assigning to. That returns the object, which is truthy. I would expect that to throw an error, which it does in the console:
Uncaught SyntaxError: Invalid destructuring assignment target
The literal shouldn't be a valid target, but a transpiler would most likely break that.

The if statement executes because you are basically doing assignment inside if statement which always return the assigned value which in this case is {} which evaluates to true.
var b
if(b={}){console.log("what!!")}
function a(){
var car={}
return {undefinedProp: es6Magic} = car;
}
console.log(a())

Related

Why does this expression result in `ReferenceError`?

Why does incrementing the same thing behave differently when I reference it via a variable?
function f() {
return {};
}
let x = {};
x++; // OK
(f())++ // ReferenceError
The difference is due to that when js is evaluating the expression it starts by checking if the left hand side is convertible to a number and by quirkyness an object is converted to Nan whereas a function is is not and js throws an exception when trying to convert it before it is evaluated.
See also here:
https://tc39.es/ecma262/multipage/ecmascript-language-expressions.html#sec-postfix-increment-operator
This whole code doesn't make any sense. You cannot increment a object.

Assigning value to undefined in JavaScript

I was writing some code in JavaScript. When I accidentally came across this.
undefined = 'some value' //does not give any error
true = 'some value'; //gives error
null = 'some value'; //gives error
How is it that first statement is valid whereas the other two are invalid. From what I know both undefined, true, and null are values you can assign to some variable, so all these should be invalid statements.
From MDN:
undefined is a property of the global object; i.e., it is a variable
in global scope. The initial value of undefined is the primitive value
undefined.
Hence, you can assign the value to undefined unlike true and null which are reserved keywords. Note that this is the same case with NaN as well which is again not a reserved keyword and hence, you can assign any value to it.
Just to add more to this, it doesn't matter even if you are assigning a value to undefined, it will not write to it as it is a readonly property.
Quoting from MDN again.
In modern browsers (JavaScript 1.8.5 / Firefox 4+), undefined is a
non-configurable, non-writable property per the ECMAScript 5
specification. Even when this is not the case, avoid overriding it.
Prefer using strict-mode in your JavaScript by declaring "use strict" at the very top of the file or inside a function to avoid such things. Using something like
"use strict";
undefined = 'test'; //will raise an error, refer to [1]
[1] VM1082:2 Uncaught TypeError: Cannot assign to read
only property 'undefined' of object '#'
This is because undefined is not a reserved word in JavaScript, even though it has a special meaning. So it can be assigned a value and the whole statement is valid. Whereas true and null are reserved words and can't be assigned values.
For reference: JavaScript Reserved Words
I quote directly from the MD Js docs.
While it is possible to use it as an identifier (variable name) in any
scope other than the global scope (because undefined is not a reserved
word), doing so is a very bad idea that will make your code difficult
to maintain and debug.
//DON'T DO THIS
// logs "foo string"
(function() { var undefined = 'foo'; console.log(undefined, typeof undefined); })();
// logs "foo string"
(function(undefined) { console.log(undefined, typeof undefined); })('foo');
https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/undefined
You can not declare a variable with the name of reserved words(keywords) in any language either it's scripting or programming.
if you want to use this you can use _ underscore at the very first of the varibale name.
like: _true , _null or _anythingwhatyouwant

why javascript let NaN can be overrided in function?

I tested this code in chrome 56
I just found this weird code.
if I type this code in console const NaN = '';
I got this message that I expected. Uncaught SyntaxError: Identifier 'NaN' has already been declared at <anonymous>:1:1
but, if I override NaN keyword in function, like this
function a(){ const NaN = ''; return NaN; }
it returns empty string ''
why javascript let keywords can be overrided in function?
According to the MDN docs:
NaN is a property of the global object, i.e. it is a variable in global scope.
It's not rewriteable, you can't assign any other value to it.
Note that it's actually possible, but not in the global scope. If you would do it inside a function, you are able then to overwrite it's value and access it, but only inside the function scope. Even if you have reassigned values to the NaN property inside the function, the global object won't be affected.
The same is concerned with e.g. Infinity.
Don't be misleaded with the const keyword, it's not possible whether with let or var, but what worths mentioning - using var won't throw any errors, but the global object still won't be overwrited though.
(function() {
const NaN = 'something';
const Infinity = '5';
console.log(NaN);
console.log(Infinity);
})();
console.log(NaN); //hasn't been overwrited
console.log(Infinity); //hasn't been overwrited
//const NaN = ''; --> throws error (has already been declared)
//const Infinity = 5; --> throws error (has already been declared)
From MDN Documentation:
NaN is a property of the global object. The initial value of NaN is
Not-A-Number — the same as the value of Number.NaN. In modern
browsers, NaN is a non-configurable, non-writable property. Even when
this is not the case, avoid overriding it.
The documentation tells that it is non-configurable and non-writable in all modern browser and even if possible you should avoid changing it.

What do braces do in JavaScript?

I read this line in Eloquent JavaScript and would love some clarity.
...braces have two meanings in JavaScript. At the start of a statement, they start a block fo statements. In any other position, they describe an object. Fortunately, it is almost never useful to start a statement with a brace object, and...
So, braces in let's say a..... an 'if statement' create a block of statements to execute, but braces that appear in let's say a function call (as a parameter) or in a variable assignment becomes an object literal.
Is that right? What are all the other cases? I'm not sure I understand the rule for when braces bundle up statements and for when they describe an object.
as object literals
var a = {field1:value1, field2:value2}
as function bodies
function func() {
// do something
}
var f = function() { /* do something */ };
var f = ()=>{}; // ditto
where the first item in the statement is an object literal
// {}.toString(); // syntax error, first brace of statement = code block
({}).toString(); // correct
as destructured assignment
var obj = {a:1, b:2, c:3};
var {a:x, c:y} = obj; // assign obj.a to x, and obj.c to y
({a:x, c:y} = obj); // ditto
Note - this has a lot of forms so I won't cover them all, full info found here (thanks RobG)
how this is interpreted
You can assume that all your JS code is inside some {} block. So the start of your code is immediately after a { always.
Wherever a value is expected, {} does not mean a function body. At the start of a statement this is ambiguous because you can have anonymous code blocks like so:
var x = 1;
{
var x = x+2;
// x = 3
}
// x = 3 (!)
This is archaic from C-style syntax where this would influence scope, but in testing this in JS it doesn't seem to have that effect, so for all intents it's rather useless syntax except to identify a code block. If you wanted such behavior you'd need to do this:
var x = 1;
(()=>{
var x = x+2;
// x = 3
})()
// x = 1
If we need an object first in some statement, we need to clarify to JS that we want a value. This is why we use ({}) instead of {}, because the former is unambiguously an object literal inside parens.
a simpler explanation
Rather than examine when {} is parsed as a value, let's look at when it isn't. There are two cases in general where we don't treat {} as an object literal: as a function body or as a statement group (my own term).
Consider the general control statements - if, for, while, with etc. These can all* be used in a way that completely avoids {}. In this respect {} should be thought of as statement groups hence the term.
if (x) x++; else x--;
if (x) {x++;} else {x--;}
{if (x) {x++;} else {x--;}}
*note: switch is an exception, switch(1); gives an error SyntaxError: missing { before switch body
Using this rule it then makes sense why we must use () to denote an object literal if it's the start of a statement - we can't start a statement in (), so you can't start a statement group there either, leaving only one option (object literal or related syntax).
This leaves function bodies.
function bodies
First, consider a function declaration statement:
function f () {}
It doesn't need a semicolon (;). This means the entire thing is a single statement. This explains why the following gives a syntax error in the first form but not the second:
function(){return 1;}(); // error: function statement requires name
var x = function(){return 1;}(); // fine
This is because the first is parsed as a statement, and a function declaration statement cannot be anonymous. However the second is in a value context and is treated as such. The situation is identical as with object literals, if it could be a statement it cannot be a value, but if we're already knee deep in value land, it has to be a value.
The => notation is, with one exception, parsed identically to function. The ()=>{} form is identical but in practice differs because this type of function cannot have a this object - it cannot be an object method (doesn't make much sense to) and it cannot construct new objects (it has no prototype), and other quirks as a result. otherwise it's straightforward to see how it's the same as function(){}.
()=>... however is a little different. It's treated as ()=>{return ...}. But, without the explicit } to finish the return statement, the syntax greedily captures the largest expression that would parse as such (not necessarily work). Case in point:
()=>1; // statement; = function that returns "1"
()=>1(); // statement; = function that returns "1()"
(()=>1()); // TypeError: 1 is not a function
(()=>1)(); // what was intended in above (you'd hope)

"var variable" returns undefined?

When I run "var variable = true;" in chrome console I get "undefined" returned:
> var variable = true;
undefined
But when I run without "var" it returns true:
> variable = true;
true
Why is it returning "undefined" with "var"?
It's confusing cause I expected it would return true.
The first is a statement, while the second is an expression. While not quite the same, it is similar to C's rules:
// A statement that has no value.
int x = 5;
// An expression...
x = 10;
// ...that can be passed around.
printf("%d\n", x = 15);
var x = y; is a statement which returns no value. In the WebKit JS console, a statement that returns no value will show undefined as the result, e.g.
> if(1){}
undefined
> ;
undefined
> if(1){4} // this statement returns values!
4
The assignment is an expression which returns the value of the LHS. That means, this expression statement has a return value, and this will be shown.
An assignation returns the assignation's value, but with var this return is "consumed" (?)
Statements always return undefined.
var color = "red";
undefined
Expressions always return a value.
color = "orange";
"orange"
I'd like to point out, that the answer provided by kennytm should be the accepted answer, at least for pedagogical purposes. The accepted answer doesn't answer why this is the case or provide deeper understanding.
Like the null value in JavaScript, undefined indicates absence of value, but in a much deeper way. The following should be taken as complimentary to the above-mentioned answers:
undefined is the value of variables that haven't been initialized and the
value you get when you query the value of an object property or
array element that doesn't exist. This value is also returned by
functions that have no return value, and the value of function
parameters for which no argument is supplied. undefined is a predefined
global variable (not a language keyword like null) that is initialized
to the undefined value.
You might consider undefined to represent a system-level, unexpected,
or error-like absence of value and null to represent program-level,
normal, or expected absence of value.
-- Flanagan, David. JavaScript: The Definitive Guide: Activate Your Web
Pages (Definitive Guides) . O'Reilly Media. Kindle Edition.
Also, makes sure to check out both the accepted and the second most voted answer for further reference:
Chrome/Firefox console.log always appends a line saying undefined

Categories

Resources