Today I figured out that it is possible to use operations before the parenthesis of a function call.
E.g.
console.log|('Hello world!');
or
console.log>>(33);
Why is this possible and what happens?
Like in most "algol-like" languages, parentheses have multiple meanings in javascript:
grouping operator, as in 2 * (3 + 4)
function call operator, as in console.log(5)
part of function declaration syntax: function(x) {}
When you insert an operator between a function name and a function call parenthesis, this one becomes the grouping operator. It's not a function call anymore. So func(args) turns into func op (args), which is syntactically a valid expression, because functions are "first-class citizens" in javascript and can be used in expressions like any other value. Whether it makes sense is another question though, because, apart from +, operators don't produce anything meaningful when applied to functions.
Simply put: because an operator works on operands, and functions are, in JS at least, first class objects (meaning they can be passed around, and returned, and operated on).
To do so, you'll of course need to use operators. A simple, not too far fetched example:
function foo()
{
return foo.bar;//. is an operator
}
console.log(foo());//logs undefined
foo.bar = '123';//again, the . operator
console.log(foo());//logs 123
What happens in your case, however, is JS will evaluate both operands (the expressions on either side of the operator):
console.log (LOperand)
| (operator)
('hello world') (ROperand, to be evaluated further still because of the grouping operator ())
And attempt to evaluate them to compatible types for the operator to do its work. console.log is an object, a function instance in fact. hello world is a string constant inside a the grouping operator.
How these types will be coerced and evaluated is specified in the ECMAScript standard (google it), but bottom line, the function (console.log) could well be coerced to a string (as if you'd call console.log.toString(), which gives "function log() { [native code] }" on chromium). The upshot is that the code behaves the same as:
"function log() { [native code] }"|"Hello world"
which yields 0
Actually, you are not executing the function, you are just evaluating an expression (that makes no sense at all)
The console.log|('Hello world!'), will be evaluated as:
[native function] | 'Hello world!'
Which makes no sense, since "|" is a bitwise operator. Same as the other example that you gave.
So, you are not placing the operator between the function call. You are separating the values, and no longer performing the expected action (funcion call).
It is possible to use operations before the parenthesis of a function call.
Not quite so,
console.log|('Hello world!');
is equivalent to
console.log | 'Hello world!';
which has a different meaning than you intended :)
('Hello world!') is the same as 'Hello world!' and | is the bitwise OR operator in JavaScript (left | right will match the left operand with the right operand bit by bit).
In your example, console.log without parenthesis returns the function itself (as opposed to console.log() which returns undefined), so you are basically [Function] | 'Hello world!'.
Related
I have a twofold question which involves something I would consider to be incorrect Javascript code.
How is the following statement interpreted in Javascript, and why?
(1,2,3,4)
Why is there a difference between these two invocations:
var a = (1,2,3,4);
a();
which leads to a being equal to 4 and Uncaught TypeError: a is not a function being thrown, and
(1,2,3,4)();
which leads to Uncaught TypeError: (((1 , 2) , 3) , 4) is not a function?
How is the following statement interpreted in Javascript, and why?
(1,2,3,4)
That's a comma operator expression (actually, a chain of them) wrapped in grouping parentheses. The comma operator is quite unusual: It evalutes both of its operands, then takes the value of the second one as its value, throwing away the value of the first one. You have a chain of them there, so the value of 1 is evaluated, then 2, then 3, then 4, and the result of the comma operator chain is the value 4; the result of the grouped parentheses expression is therefore 4.
Why is there a difference between these two invocations:
var a = (1,2,3,4);
a();
Because of the syntax of the language. In the first case, it's clearly not a function call, as there's no value prior to the first ( to call. The parsing rules for a complex language like JavaScript are just that: Complex. The parser is context-sensitive, and knows how to differentiate between grouping parentheses and function-call parentheses.
which leads to a being equal to 4 and Uncaught TypeError: a is not a function being thrown, and
(1,2,3,4)();
which leads to Uncaught TypeError: (((1 , 2) , 3) , 4) is not a function?
In both cases, the error message is quoting the expression that yielded the result it then tried to call as a function.
There is an operator in JS (among other languages) called the comma operator. It simply takes two operands, and returns the rightmost one.
a = 1, 2; // a now equals 2
It is, however, not the same comma as the function parameter separator. It is an operator.
The comma operator evaluates each of its operands (from left to right) and returns the value of the last operand.
So, the statement (1,2,3,4); returns 4, so var a = (1,2,3,4); means that a is equal to 4 which, is not a function, thus the error.
Likewise, (1,2,3,4) is just a grouping of comma operators and not a function, thus the second error.
For example, in both Wat and in my Chrome browser:
{} + {}
is NaN
But in Node REPL, it's
[object Object][object Object]
The latter admittedly makes more sense to me - coercing to string and then acting is a pretty reasonable thing to do. However I don't understand where this discrepancy comes from, and therefore, don't understand how much I can trust the REPL to understand some simple JS behavior.
{} is both an expression (an empty object literal) and a statement (an empty block).
eval() will try to parse its input as a statement.
If it isn't a "normal" statement (eg, an if), it will be parsed as an expression statement, which evaluates an expression.
Therefore, {} + {} is parsed as two statements (via ASI): {}; +{}. The first statement is an empty block; the second statement is the unary + operator which coerces an object to a number.
Coercing an object to a number involves calling toString() (which returns "[object Object]"), then parsing the result as a number (which it isn't).
eval() then returns that as the value of the final statement.
Node wraps its REPL input in () to force it to be parsed as an expression:
// First we attempt to eval as expression with parens.
// This catches '{a : 1}' properly.
self.eval('(' + evalCmd + ')',
I have a twofold question which involves something I would consider to be incorrect Javascript code.
How is the following statement interpreted in Javascript, and why?
(1,2,3,4)
Why is there a difference between these two invocations:
var a = (1,2,3,4);
a();
which leads to a being equal to 4 and Uncaught TypeError: a is not a function being thrown, and
(1,2,3,4)();
which leads to Uncaught TypeError: (((1 , 2) , 3) , 4) is not a function?
How is the following statement interpreted in Javascript, and why?
(1,2,3,4)
That's a comma operator expression (actually, a chain of them) wrapped in grouping parentheses. The comma operator is quite unusual: It evalutes both of its operands, then takes the value of the second one as its value, throwing away the value of the first one. You have a chain of them there, so the value of 1 is evaluated, then 2, then 3, then 4, and the result of the comma operator chain is the value 4; the result of the grouped parentheses expression is therefore 4.
Why is there a difference between these two invocations:
var a = (1,2,3,4);
a();
Because of the syntax of the language. In the first case, it's clearly not a function call, as there's no value prior to the first ( to call. The parsing rules for a complex language like JavaScript are just that: Complex. The parser is context-sensitive, and knows how to differentiate between grouping parentheses and function-call parentheses.
which leads to a being equal to 4 and Uncaught TypeError: a is not a function being thrown, and
(1,2,3,4)();
which leads to Uncaught TypeError: (((1 , 2) , 3) , 4) is not a function?
In both cases, the error message is quoting the expression that yielded the result it then tried to call as a function.
There is an operator in JS (among other languages) called the comma operator. It simply takes two operands, and returns the rightmost one.
a = 1, 2; // a now equals 2
It is, however, not the same comma as the function parameter separator. It is an operator.
The comma operator evaluates each of its operands (from left to right) and returns the value of the last operand.
So, the statement (1,2,3,4); returns 4, so var a = (1,2,3,4); means that a is equal to 4 which, is not a function, thus the error.
Likewise, (1,2,3,4) is just a grouping of comma operators and not a function, thus the second error.
This question already has answers here:
Understanding JavaScript Truthy and Falsy
(9 answers)
Closed 12 months ago.
I wasn't really sure what to name this question, as that is almost the question itself.
Basically I was messing with some code and found something that I can't quite explain. Here's a simplification:
function foo (a, b) {
if (foo) {
console.log("foo is true");
} else if (!foo) {
console.log("foo is false");
}
}
foo();
This outputs "foo is true", but what I don't understand is how is Js evaluating a function without executing it ( lack of (); ) and how can I execute it even without passing parameters defined in the function.
Maybe I should say that the only language I really know is java.
It's simple:
Functions are just objects with an internal [[Call]] method.
All objects produce true when coerced to booleans.
In JavaScript, a function is a value (a somewhat special value, that you can call, using the () operator). In JavaScript, the following values are "false" when evaluated in a boolean context:
false
0
""
undefined
null
NaN
All other values are "true". Therefore, a function is always "true".
It is evaluating the reference to the function that the identifier foo is currently referring to. JavaScript uses object references to point to functions and variables, that you can change quite easily. This allows you to check which function you are currently referencing.
In Java your code would not be legal because the parameter signature has to match the function's parameter signature which includes the name of the function, and its parameter list.
In Javascript the only thing that matters is the name of the function. There is NO overloading in Javascript. This makes sense because Javascript's object model is based off of string -> function/property maps. Java's object model is more complex and nuanced which is why you can do overloading.
So in short. foo() will call your function foo, with a and b being undefined. If you call it with foo(5) a would be 5, and b would be undefined. If you called it with foo(5, 1, 3) a would be 5, b would be 1 and 3 would be ignored. I would guess that you can probably get at 3rd argument using the Javascript arguments variable. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments
Since a and b are undefined in your example, they evaluate to false. When you evaluate if(foo) you're passing the function object into the if() condition, and defined objects always evaluate to true. null and undefined both evaluate to false.
All falsey values in JavaScript
In javascript you're not required to pass any function arguments. When an argument is not passed the value of that argument is assumed to be undefined. It also prints "foo is true" because foo is defined as the function foo. You can see whats going on by running the following
function foo (a, b) {
console.log(typeof a);
console.log(typeof b);
console.log(typeof foo);
}
foo();
//it prints:
//undefined
//undefined
//function
Basically calling foo(); is like calling foo(undefined,undefined);
could someone please explain to me what is going on in the second line here ? :
var foo = function(){alert("hello?")};
(0,foo)();
The infamous comma expression a,b evaluates both arguments and returns the value of the right-hand expression.
Hence in this case it's exactly the same as foo();.
Here's a better example that will help you understand what's going on:
function foo() {
print("foo called");
return 123;
}
function bar() {
print("bar called");
return 456;
}
var result = (foo(), bar());
print("result:", result);
Output:
foo called
bar called
result: 456
Also the comma expression may be confused with the comma delimiting function arguments. Not the same! Notice the difference:
print("result:", foo(), bar() ); // 3 arguments, no comma operator
print("result:", (foo(), bar()) ); // 2 arguments, comma operator
It's evaluating both expressions in the first parenthesis and executing the second one (in this case - a function).
https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Operators/Comma_Operator
Since the Comma operator in javascript evaluates multiple operands and returns the last one. MDN:
The comma operator evaluates both of its operands (from left to right) and returns the value of the second operand.
Your expression (0,foo)
returns foo which then is invoked by the paranthesis, put after it.
the comma will evaluate operands and return the last one
the second line will return foo