为什么{} + {}仅在客户端是NaN?为什么不在Node.js? [英] Why {} + {} is NaN only on the client side? Why not in Node.js?

查看:410
本文介绍了为什么{} + {}仅在客户端是NaN?为什么不在Node.js?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

虽然 [] + [] 是一个空字符串, [] + {} [object Object] {} + [] 0 。为什么 {} + {} NaN?

While [] + [] is an empty string, [] + {} is "[object Object]", and {} + [] is 0. Why is {} + {} NaN?

> {} + {}
  NaN

我的问题不是为什么({} + {})。toString()[object Object] [object Object] NaN.toString()NaN这部分已经有了答案

My question isn't why ({} + {}).toString() is "[object Object][object Object]" while NaN.toString() is "NaN", this part has an answer here already.

我的问题是为什么这只发生在客户端?在服务器端( Node.js {} + { } [object Object] [object Object]

My question is why does this happen only on the client side? On the server side (Node.js) {} + {} is "[object Object][object Object]".

> {} + {}
'[object Object][object Object]'






总结

在客户端:

 [] + []              // Returns ""
 [] + {}              // Returns "[object Object]"
 {} + []              // Returns 0
 {} + {}              // Returns NaN

 NaN.toString()       // Returns "NaN"
 ({} + {}).toString() // Returns "[object Object][object Object]"
 var a = {} + {};     // 'a' will be "[object Object][object Object]"

在Node.js中:

 [] + []   // Returns "" (like on the client)
 [] + {}   // Returns "[object Object]" (like on the client)
 {} + []   // Returns "[object Object]" (not like on the client)
 {} + {}   // Returns "[object Object][object Object]" (not like on the client)


推荐答案

更新的说明:此问题已修复Chrome 49

非常有趣的问题!让我们深入研究。

Very interesting question! Let's dig in.

差异的根源在于Node.js如何评估这些陈述与Chrome开发工具的工作方式。

The root of the difference is in how Node.js evaluates these statements vs. how the Chrome development tools do.

Node.js使用 repl 模块。

Node.js uses the repl module for this.

来自Node.js REPL源代码

From the Node.js REPL source code:

self.eval(
    '(' + evalCmd + ')',
    self.context,
    'repl',
    function (e, ret) {
        if (e && !isSyntaxError(e))
            return finish(e);
        if (typeof ret === 'function' && /^[\r\n\s]*function/.test(evalCmd) || e) {
            // Now as statement without parens.
            self.eval(evalCmd, self.context, 'repl', finish);
        }
        else {
            finish(null, ret);
        }
    }
);

这就像运行({} + {})在Chrome开发者工具中,也可以按照您的预期生成[object Object] [object Object]

This acts just like running ({}+{}) in the Chrome developer tools, which also produces "[object Object][object Object]" as you'd expect.

另一方面 Chrome dveloper工具执行以下操作

try {
    if (injectCommandLineAPI && inspectedWindow.console) {
        inspectedWindow.console._commandLineAPI = new CommandLineAPI(this._commandLineAPIImpl, isEvalOnCallFrame ? object : null);
        expression = "with ((window && window.console && window.console._commandLineAPI) || {}) {\n" + expression + "\n}";
    }
    var result = evalFunction.call(object, expression);
    if (objectGroup === "console")
        this._lastResult = result;
    return result;
}
finally {
    if (injectCommandLineAPI && inspectedWindow.console)
        delete inspectedWindow.console._commandLineAPI;
}

所以基本上,它执行电话在带有表达式的对象上。表达式为:

So basically, it performs a call on the object with the expression. The expression being:

with ((window && window.console && window.console._commandLineAPI) || {}) {
    {}+{};// <-- This is your code
}

因此,正如您所看到的,表达式是直接计算的,没有包装括号。

So, as you can see, the expression is being evaluted directly, without the wrapping parenthesis.

Node.js的来源证明了这一点:

Node.js's source justifies this:

// This catches '{a : 1}' properly.

节点并不总是这样。这是改变它的实际提交。 Ryan在更改中留下了以下评论:通过差异示例改进REPL命令的改进方式。

Node did not always act like this. Here is the actual commit that changed it. Ryan left the following comment on the change: "Improve how REPL commands are evaled" with an example of the difference.

更新 - OP对 Rhino 的行为感兴趣(以及为什么它的行为与Chrome devtools和nodejs不同)。

Update - OP was interested in how Rhino behaves (and why it behaves like the Chrome devtools and unlike nodejs).

Rhino使用完全不同的JS引擎,不像Chrome开发者工具和Node.js的REPL都使用V8。

Rhino uses a completely different JS engine unlike the Chrome developer tools and Node.js's REPL which both use V8.

这是当您在Rhino shell中使用Rhino评估JavaScript命令时会发生什么的基本管道。

Here is the basic pipe line of what happens when you eval a JavaScript command with Rhino in the Rhino shell.

反过来,它调用这个 new IProxy(IProxy.EVAL_INLINE_SCRIPT); 例如,如果代码是直接使用内联开关-e传递的。

In turn, it calls this new IProxy(IProxy.EVAL_INLINE_SCRIPT); for example, if the code was passed directly with the inline switch -e.

这打到了IProxy的 运行 方法。

This hits IProxy's run method.

它调用 evalInlineScript src )。这只是简单地编译字符串并进行篡改。

It invokes evalInlineScript (src). This simply compiles the string and evals it.

基本上:

Script script = cx.compileString(scriptText, "<command>", 1, null);
if (script != null) {
    script.exec(cx, getShellScope()); // <- just an eval
}

在这三个中,Rhino的shell是没有任何包装的那个与实际的 eval 最接近的东西。 Rhino是最接近实际的 eval()语句,你可以预期它的行为与 eval 一样。

Out of the three, Rhino's shell is the one that does the closest thing to an actual eval without any wrapping. Rhino's is the closest to an actual eval() statement and you can expect it to behave exactly like eval would.

这篇关于为什么{} + {}仅在客户端是NaN?为什么不在Node.js?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆