Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does calling a function in the Node.js REPL with )( work?

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?

like image 968
hyde Avatar asked Oct 11 '13 05:10

hyde


People also ask

What is Node JS explain the working of REPL terminal?

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.

What is the use of REPL in node JS and which of the following do you comprehend to be in Favour?

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.

How do I use REPL in node?

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.


3 Answers

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';
  }
like image 119
3 revs Avatar answered Oct 11 '22 20:10

3 revs


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)
> 
like image 28
leesei Avatar answered Oct 11 '22 20:10

leesei


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.

like image 24
thefourtheye Avatar answered Oct 11 '22 22:10

thefourtheye