为什么在Node.js REPL中调用函数()工作?

hyd*_*yde 193 javascript syntax node.js

为什么可以用这样的JavaScript调用函数,用node.js测试:

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

为什么最后一次通话hi)(有效?它是node.js中的bug,V8引擎中的bug,官方未定义的行为,还是所有解释器的实际有效JavaScript?

Jon*_*ski 201

这是由于REPL如何评估输入,最终是:

(hi)()
Run Code Online (Sandbox Code Playgroud)

添加附加括号以强制它为表达式:

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

目的是将其{...}视为Object文字/ 初始化者而不是.

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

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

并且,正如leesei所提到的,这已经改为0.11.x,它将包装{ ... }而不是所有输入:

  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';
  }
Run Code Online (Sandbox Code Playgroud)

  • 这是否意味着'hi)(arg`会起作用吗?这可能会被滥用来编写一些真正的WTF代码;-) (19认同)
  • `hi)(arg`成为`(hi)(arg)` - 没什么比不上的 (2认同)

lee*_*sei 84

似乎是一个Node REPL错误,将这两行放在一个.js会导致语法错误.

function hi() { console.log("Hello, World!"); }
hi)(
Run Code Online (Sandbox Code Playgroud)

错误:

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
Run Code Online (Sandbox Code Playgroud)

提交的问题#6634.

转载于v0.10.20.


v0.11.7已修复此问题.

$ 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)
> 
Run Code Online (Sandbox Code Playgroud)

  • 不,不是真的.实际上,这是一个笑话. (40认同)
  • 他们真的继续前进并修好了吗?哇,可惜,我真的很想看到它开始一种文化,成为所有语言的_feature_.我打了多少次)(而不是()匆忙... :)) (27认同)
  • @geomagas你认为`函数a)arg1,arg2(}] arg2 + arg1 [return; {`应该是有效的语法? (18认同)
  • 曾几何时,有一个带有DWIM选项的Lisp实现可以自动纠正拼写错误和其他小错误.http://en.wikipedia.org/wiki/DWIM (7认同)
  • @geomagas,好吧,有些人已经开始思考它了 - "npm"有`install`**和**`isntall`.打赌你没注意到:) (2认同)

the*_*eye 60

4个月前有一个错误,针对此问题https://github.com/joyent/node/issues/5698

问题是因为,REPL用parens包含了这些陈述.所以

foo)(
Run Code Online (Sandbox Code Playgroud)

(foo)()
Run Code Online (Sandbox Code Playgroud)

可在此处找到实际说明https://github.com/joyent/node/issues/5698#issuecomment-19487718.

  • 我认为自动分号插入很糟糕. (75认同)