development

왜 {} + {}가 클라이언트 측에서만 NaN입니까?

big-blog 2020. 6. 26. 07:45
반응형

왜 {} + {}가 클라이언트 측에서만 NaN입니까? Node.js에없는 이유는 무엇입니까?


While [] + []은 빈 문자열이며 [] + {}is "[object Object]"이며 {} + []is 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의 기능

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가 다르게 작동하는 이유

Node.js의 소스는 이것을 정당화합니다.

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

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.


Rhino

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

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

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

Basically:

Script script = cx.compileString(scriptText, "<command>", 1, null);
if (script != null) {
    script.exec(cx, getShellScope()); // <- just an 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.

참고URL : https://stackoverflow.com/questions/17268468/why-is-nan-only-on-the-client-side-why-not-in-node-js

반응형