Warum funktioniert das Aufrufen einer Funktion in der Node.js REPL mit) (?

191

Warum ist es möglich, Funktionen in JavaScript wie folgt aufzurufen, die mit node.js getestet wurden:

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

Warum funktioniert der letzte Anruf hi)(? Ist es ein Fehler in node.js, ein Fehler in der V8-Engine, ein offiziell undefiniertes Verhalten oder tatsächlich gültiges JavaScript für alle Interpreter?

Hyde
quelle
1
reproduzierbar in nodejs v0.6.19 unter Ubuntu 13.04
mvp
1
Ein schneller Test auf jsfiddle.net zeigt Ihnen, dass es sich um ungültiges JavaScript handelt.
Christophe
6
Scheint ein Node REPL-Fehler zu sein, das .js
Einfügen
8
Übrigens, Kredit, wo es fällig ist, kam dies bei irc (FreeNode #nodejs), von @miniml
hyde
3
Perl hat aus dem gleichen Grund etwas Ähnliches : perl -ne '$x += $_; }{ print $x'. Siehe versteckte Funktionen von Perl
Adrian Pronk

Antworten:

84

Scheint ein Node REPL-Fehler zu sein. Wenn Sie diese beiden Zeilen in einen Fehler setzen, wird dies zu einem .jsSyntaxfehler führen.

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

Ausgabe eingereicht # 6634 .

Wiedergabe am v0.10.20.


v0.11.7 haben dies behoben.

$ 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
quelle
27
Sie gingen tatsächlich voran und reparierten es? Awwww, schade, ich würde wirklich gerne sehen, dass daraus eine Kultur entsteht und ein Feature in allen Sprachen wird. Wie oft habe ich getippt) (statt () in Eile ... :))
Geomagas
18
@geomagas Du denkst, function a)arg1, arg2( } ]arg2 + arg1[ return; {sollte eine gültige Syntax sein?
Azz
40
Nein nicht wirklich. Eigentlich war das ein Witz.
Geomagas
7
Es war einmal eine Lisp-Implementierung mit einer DWIM-Option, die Rechtschreibfehler und andere kleinere Fehler automatisch korrigierte. en.wikipedia.org/wiki/DWIM
Barmar
2
@geomagas, na ja, einige haben schon darüber nachgedacht - npmhat install und isntall . Ich wette, du hast es nicht bemerkt :)
Eliran Malka
201

Dies liegt daran, wie die REPL die Eingabe bewertet, was letztendlich wie folgt lautet:

(hi)()

Die zusätzlichen Klammern werden hinzugefügt, um zu erzwingen, dass es sich um einen Ausdruck handelt :

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

Die Absicht ist, {...}als ObjectLiterale / Initialisierer und nicht als Block zu behandeln .

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

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

Und wie Leesei erwähnt hat, wurde dies für 0.11.x geändert, wodurch nur{ ... } alle Eingaben umbrochen werden:

  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';
  }
Jonathan Lonowski
quelle
19
Bedeutet das, dass hi)(argdas funktionieren wird? Das könnte missbraucht werden, um einen wirklich WTF-gesteuerten Code zu schreiben ;-)
Doctor Jones
Ich verstehe immer noch nicht, warum das laufen würde. Würde es nicht einen Syntaxfehler wegen des unübertroffenen offenen Parens geben?
Peter Olson
2
hi)(argwird (hi)(arg)- nichts Unübertroffenes
SheetJS