¿Por qué llamar a una función en Node.js REPL con) (funciona)?

191

¿Por qué es posible llamar a la función en JavaScript de esta manera, probado con node.js:

~$ node
> function hi() { console.log("Hello, World!"); };
undefined
> hi
[Function: hi]
> hi()
Hello, World!
undefined
> hi)( // WTF?
Hello, World!
undefined
>

¿Por qué funciona la última llamada hi)(? ¿Es un error en node.js, un error en el motor V8, un comportamiento oficialmente indefinido o un JavaScript realmente válido para todos los intérpretes?

Hyde
fuente
1
reproducible en nodejs v0.6.19 en Ubuntu 13.04
mvp
1
una prueba rápida en jsfiddle.net le mostrará que es JavaScript no válido.
Christophe
66
Parece ser un error de Node REPL, poner las dos líneas en un .jscausará un error de sintaxis
leesei
8
Por cierto, crédito donde es debido, esto surgió en irc (FreeNode #nodejs), por @miniml
hyde
3
Perl tiene algo similar por la misma razón: perl -ne '$x += $_; }{ print $x'. Ver características ocultas de Perl
Adrian Pronk

Respuestas:

84

Parece ser un error de Node REPL, poner estas dos líneas en un .jscausará un error de sintaxis.

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

Problema enviado # 6634 .

Reproducido en v0.10.20.


v0.11.7 tiene esto arreglado.

$ 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)
> 
leesei
fuente
27
¿En realidad se adelantaron y lo arreglaron? Awwww, lástima, realmente me gustaría verlo comenzar una cultura y convertirse en una característica en todos los idiomas. ¿Cuántas veces he escrito) (en lugar de () a toda prisa ... :))
geomagas
18
@geomagas ¿Crees que function a)arg1, arg2( } ]arg2 + arg1[ return; {debería ser una sintaxis válida?
azz
40
No en realidad no. En realidad, eso fue una broma.
geomagas
77
Érase una vez una implementación de Lisp con una opción DWIM que corrigió automáticamente errores ortográficos y otros errores menores. en.wikipedia.org/wiki/DWIM
Barmar
2
@geomagas, bueno, algunos ya se adelantaron y pensaron en ello, npmtiene install y isntall . apuesto a que no lo has notado :)
Eliran Malka
201

Se debe a cómo REPL evalúa la entrada, que en última instancia es como:

(hi)()

Los paréntesis adicionales se agregan para forzarlo a ser una Expresión :

  // First we attempt to eval as expression with parens.
  // This catches '{a : 1}' properly.
  self.eval('(' + evalCmd + ')',
      // ...

La intención es tratar {...}como Objectliterales / inicializadores en lugar de como un bloque .

var stmt = '{ "foo": "bar" }';
var expr = '(' + stmt + ')';

console.log(eval(expr)); // Object {foo: "bar"}
console.log(eval(stmt)); // SyntaxError: Unexpected token :

Y, como mencionó leesei, esto se ha cambiado para 0.11.x, que solo ajustará en{ ... } lugar de toda la entrada:

  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';
  }
revs Jonathan Lonowski
fuente
19
¿Eso significa que hi)(argfuncionará? Se podría abusar de eso para escribir un código realmente lleno de WTF ;-)
Doctor Jones
Todavía no entiendo por qué eso funcionaría. ¿No sería un error de sintaxis debido a la incomparable par abierto?
Peter Olson
2
hi)(argse convierte en (hi)(arg)- nada sin igual
SheetJS