Why is it possible to call function in JavaScript like this, tested with node.js:
~$ node
> function hi() { console.log("Hello, World!"); };
undefined
> hi
[Function: hi]
> hi()
Hello, World!
undefined
> hi)( // WTF?
Hello, World!
undefined
>
Why does the last call, hi)(
, work? Is it bug in node.js, bug in V8 engine, officially undefined behaviour, or actually valid JavaScript for all interpreters?
The Node. js Read-Eval-Print-Loop (REPL) is an interactive shell that processes Node. js expressions. The shell reads JavaScript code the user enters, evaluates the result of interpreting the line of code, prints the result to the user, and loops until the user signals to quit. The REPL is bundled with every Node.
js Read-Eval-Print-Loop (REPL) is an easy-to-use command-line tool, used for processing Node. js expressions. It captures the user's JavaScript code inputs, interprets, and evaluates the result of this code. It displays the result to the screen, and repeats the process till the user quits the shell.
Starting the REPL is simple - just run node on the command line without a filename. It then drops you into a simple prompt ('>') where you can type any JavaScript command you wish. As in most shells, you can press the up and down arrow keys to scroll through your command history and modify previous commands.
It's due to how the REPL evaluates the input, which is ultimately as:
(hi)()
The additional parenthesis are added to force it to be an Expression:
// First we attempt to eval as expression with parens.
// This catches '{a : 1}' properly.
self.eval('(' + evalCmd + ')',
// ...
The intent is to treat {...}
as Object
literals/initialisers rather than as a block.
var stmt = '{ "foo": "bar" }';
var expr = '(' + stmt + ')';
console.log(eval(expr)); // Object {foo: "bar"}
console.log(eval(stmt)); // SyntaxError: Unexpected token :
And, as leesei mentioned, this has been changed for 0.11.x, which will just wrap { ... }
rather than all input:
if (/^\s*\{/.test(evalCmd) && /\}\s*$/.test(evalCmd)) {
// It's confusing for `{ a : 1 }` to be interpreted as a block
// statement rather than an object literal. So, we first try
// to wrap it in parentheses, so that it will be interpreted as
// an expression.
evalCmd = '(' + evalCmd + ')\n';
} else {
// otherwise we just append a \n so that it will be either
// terminated, or continued onto the next expression if it's an
// unexpected end of input.
evalCmd = evalCmd + '\n';
}
Seems to be a Node REPL bug, putting these two lines in a .js
will cause syntax error.
function hi() { console.log("Hello, World!"); }
hi)(
Error:
SyntaxError: Unexpected token )
at Module._compile (module.js:439:25)
at Object.Module._extensions..js (module.js:474:10)
at Module.load (module.js:356:32)
at Function.Module._load (module.js:312:12)
at Function.Module.runMain (module.js:497:10)
at startup (node.js:119:16)
at node.js:901:3
Issue submitted #6634.
Reproduced on v0.10.20.
v0.11.7 have this fixed.
$ nvm run 0.11.7
Running node v0.11.7
> function hi() { console.log("Hello, World!"); }
undefined
> hi)(
SyntaxError: Unexpected token )
at Object.exports.createScript (vm.js:44:10)
at REPLServer.defaultEval (repl.js:117:23)
at REPLServer.b [as eval] (domain.js:251:18)
at Interface.<anonymous> (repl.js:277:12)
at Interface.EventEmitter.emit (events.js:103:17)
at Interface._onLine (readline.js:194:10)
at Interface._line (readline.js:523:8)
at Interface._ttyWrite (readline.js:798:14)
at ReadStream.onkeypress (readline.js:98:10)
at ReadStream.EventEmitter.emit (events.js:106:17)
>
There was a bug raised 4 months back, for this issue https://github.com/joyent/node/issues/5698
And the problem was because, REPL encloses the statements with parens. So
foo)(
becomes
(foo)()
Actual explanation can be found here https://github.com/joyent/node/issues/5698#issuecomment-19487718.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With