Pourquoi est-il possible d'appeler une fonction en JavaScript comme ceci, testé avec node.js:
~$ node
> function hi() { console.log("Hello, World!"); };
undefined
> hi
[Function: hi]
> hi()
Hello, World!
undefined
> hi)( // WTF?
Hello, World!
undefined
>
Pourquoi le dernier appel hi)(
fonctionne-t-il? Est-ce un bogue dans node.js, un bogue dans le moteur V8, un comportement officiellement non défini ou un JavaScript réellement valide pour tous les interprètes?
javascript
node.js
syntax
Hyde
la source
la source
.js
provoquera une erreur de syntaxeperl -ne '$x += $_; }{ print $x'
. Voir les fonctionnalités cachées de PerlRéponses:
Semble être un bogue Node REPL, mettre ces deux lignes dans un
.js
provoquera une erreur de syntaxe.function hi() { console.log("Hello, World!"); } hi)(
Erreur:
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
Problème soumis # 6634 .
Reproduit sur v0.10.20.
v0.11.7 a corrigé ce problème.
$ 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) >
la source
function a)arg1, arg2( } ]arg2 + arg1[ return; {
que la syntaxe devrait être valide?npm
ainstall
etisntall
. pariez que vous n'avez pas remarqué :)Cela est dû à la façon dont le REPL évalue l'entrée, qui est finalement comme:
Les parenthèses supplémentaires sont ajoutées pour le forcer à être une expression :
// First we attempt to eval as expression with parens. // This catches '{a : 1}' properly. self.eval('(' + evalCmd + ')', // ...
L'intention est de traiter
{...}
comme desObject
littéraux / initialiseurs plutôt que comme un bloc .var stmt = '{ "foo": "bar" }'; var expr = '(' + stmt + ')'; console.log(eval(expr)); // Object {foo: "bar"} console.log(eval(stmt)); // SyntaxError: Unexpected token :
Et, comme leesei l'a mentionné, cela a été changé pour 0.11.x, qui va simplement envelopper
{ ... }
plutôt que toutes les entrées: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'; }
la source
hi)(arg
fonctionnera? Cela pourrait être abusé pour écrire du code vraiment WTF ;-)hi)(arg
devient(hi)(arg)
- rien d'inégaléIl y a eu un bug soulevé il y a 4 mois, pour ce numéro https://github.com/joyent/node/issues/5698
Et le problème était que, REPL entoure les déclarations avec des parenthèses. Donc
devient
L'explication réelle peut être trouvée ici https://github.com/joyent/node/issues/5698#issuecomment-19487718 .
la source