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.
Related
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())
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)
I had read in some articles that in some languages, like in JavaScript, assignment operators can be used in conditional statements. I want to know what is the logic behind that operation? As far as I know, only comparison operators are allowed in condition checking statements.
Any expression is allowed in a condition checking statement. If the value of the expression isn't boolean, then it will be converted to boolean to determine what the statement should do.
You can for example use a number in an if statement:
if (1) { ... }
Any non-zero number will be converted to true.
In Javascript an assignment is also an expression, i.e. it has a value. The value of the expression is the same value that was assigned to the variable.
So, you can use an assignment expression in a condition checking statement, and the value of the expression is converted to boolean if needed:
if (x = 1) { ... }
Using an assignment in an condition checking statement can be useful, if the value that you assign should be used to control what happens. If you for example have a function that returns different values for the first calls, then a null when there are no more values, you can use that in a loop:
while (line = getLine()) {
document.write(line);
}
You can of couse do that with the assignment separated from the logic, but then the code gets more complicated:
while (true) {
line = getLine();
if (line == null) break;
document.write(line);
}
In JavaScript (and many other languages), when a value is assigned to a variable, the value "returned" is the value that was assigned to a variable. As such, such a statement can be used in a condition with any assigned value being evaluated in the standard way.
For example:
var y = 0;
if(x = y){
alert("Y(and thus X) is Truthy");
}
else{
alert("Y(and thus X) is Falsy");
}
There are two factors that combine to give this effect:
in many languages, including JavaScript, an expression of the form left = right evaluates to the new left. For example, a = b = c = 0 sets all of a, b, and c to zero.
in many languages, including JavaScript, a wide variety of values can be used as conditional expressions. if(7) is equivalent to if(true); so if(a = 7) is equivalent to a = 7; if(true) rather than to the presumably-intended if(a == 7).
Assigning a value with = returns that value. You can use it to make an assignment while testing if the outcome is truthy or falsey (null, 0, "" undefined, NaN, false)
if (myVar = myArgument) ...
//same as:
// myVar=myArgument;
// if (myArgument) ...
This assigns myArgument to myVar while testing myArgument. Another more specific example:
If (myVar = 3+2) ...
// same as:
// myVar=3+2;
// if (5) ...
The benefit is more compact, terse code, sometimes at the expense of clarity.
This could be used to make a condition check and also use the value after it, without writing more lines.
if (value = someFunction()) {
...
}
This is valid syntax, though highly discouraged. In quite a few languages this is explicitely forbidden, but some languages also does not make this rule (e.g. C).
Take this for example.
if (b) b = 1;
Reference Error. b is not defined. Makes sense but if I do this...
if (b) var b = 1;
I get undefined in console. and now when I look up what b is it shows as undefined.
If I try to do the same if statement again, it doesn't pass because b is neither true or false, it is undefined, but I guess my question is why does it show up as undefined? Does Javascript go through the if statement regardless if the if statement passes or fails? Thanks.
All vars gets hoisted to the beginning of the scope they are in, initialising their values to undefined. The value is then set when execution reaches the line the var was in originally.
In your second example, b gets initialised as undefined before the if is encountered, due to the var. Think of it as the same as writing the following
var b;
if (b) b = 1;
After this code is executed, b will still be undefined because it will never run into the if block as the initial value is falsy.
As mentioned by pst, this is a language specific feature of JavaScript, so don't expect the same behaviour when writing code in other languages.
JS is not going thru the if statement, but rather it's reading the if part of the statement, and since b is not defined anywhere but within the if statement, you get 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