_[] + []
_は空の文字列ですが、_[] + {}
_は_"[object Object]"
_であり、_{} + []
_は_0
_です。なぜ_{} + {}
_ NaNなのですか?
_> {} + {}
NaN
_
私の質問は、なぜ_({} + {}).toString()
_が_"[object Object][object Object]"
_であるのにNaN.toString()
が_"NaN"
_であるのではなく、 この部分にはすでに答えがあります です。
私の質問は、なぜこれがクライアント側でのみ起こるのですか?サーバー側では( Node.js )_{} + {}
_は_"[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 で修正されました。
非常に興味深い質問です!掘り下げましょう。
違いの根本は、Node.jsがこれらのステートメントを評価する方法と、Chrome開発ツールがどのように評価するかです。
Node.jsは、このために repl モジュールを使用します。
Node.jsから REPLソースコード :
_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]"
_も生成します。
一方、 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;
}
_
したがって、基本的には、式を使用してオブジェクトに対してcall
を実行します。表現は:
_with ((window && window.console && window.console._commandLineAPI) || {}) {
{}+{};// <-- This is your code
}
_
したがって、ご覧のとおり、式はラッピング括弧なしで直接評価されています。
Node.jsのソースはこれを正当化します:
_// This catches '{a : 1}' properly.
_
ノードは常にこのように動作するとは限りませんでした。 変更した実際のコミット です。ライアンは、変更について次のコメントを残しました:「REPLコマンドが評価される方法を改善する」)違いの例。
更新-OPは、Rhinoの動作に興味がありました(そして、なぜChrome devtoolsとnodejsとは異なる動作をするのか)。
Rhinoは、両方ともV8を使用するChrome開発者ツールとNode.jsのREPLとは異なり、まったく異なるJSエンジンを使用します。
RhinoシェルでRhinoを使用してJavaScriptコマンドを評価した場合の基本的なパイプラインを次に示します。
シェルは _org.mozilla.javascript.tools.Shell.main
_ を実行します。
次に、コードがインラインスイッチ-eで直接渡された場合、たとえば thisnew IProxy(IProxy.EVAL_INLINE_SCRIPT);
を呼び出します。
これは、IProxyの run
メソッドにヒットします。
evalInlineScript
( src )を呼び出します。これは単に文字列をコンパイルして評価します。
基本的に:
_Script script = cx.compileString(scriptText, "<command>", 1, null);
if (script != null) {
script.exec(cx, getShellScope()); // <- just an eval
}
_
3つのうち、Rhinoのシェルは、ラップなしで実際のeval
に最も近いものを実行します。 Rhinoは実際のeval()
ステートメントに最も近く、eval
とまったく同じように動作することが期待できます。