JS Function-constructor re-parsed everytime?

て烟熏妆下的殇ゞ 提交于 2019-12-22 10:28:53

问题


In MDN, about Functions and function scope, what does it mean by parsed every time it is evaluated? Can this be observed by codes?

Quote in the section Function constructor vs. function declaration vs. function expression:

Functions defined by function expressions and function declarations are parsed only once, while those defined by the Function constructor are not. That is, the function body string passed to the Function constructor must be parsed every time it is evaluated. Although a function expression creates a closure every time, the function body is not reparsed, so function expressions are still faster than "new Function(...)". Therefore the Function constructor should be avoided whenever possible.

It should be noted, however, that function expressions and function declarations nested within the function generated by parsing a Function constructor 's string aren't parsed repeatedly. For example:

var foo = (new Function("var bar = \'FOO!\';\nreturn(function() {\n\talert(bar);\n});"))();
foo(); //The segment "function() {\n\talert(bar);\n}" of the function body string is not re-parsed.

I have written a code snippet to (try to) test and understand it:

var bar = 'FOO!';
var foo = (new Function("return(function() {\n\talert(bar);\n});"))();
bar = 'FOO! again';
foo(); //The segment "function() {\n\talert(bar);\n}" of the function body string is not re-parsed.

var bar2 = 'FOO!2';
var foo2 = function() { alert(bar2); };
bar2 = 'FOO!2 again';
foo2();

Both two alerts the "again-version".

What does it mean by reparsed or not?

Can this be illustrated by code results?

Thanks.


FYI, i have tried another code snippet:

var bar = 'FOO!';
var string1 = "return(function() {\n\talert(bar);\n});";
var foo = (new Function(string1))();
bar = 'FOO! again';
foo(); //The segment "function() {\n\talert(bar);\n}" of the function body string is not re-parsed.
string1 = "return(function() {\n\talert(bar + ' more');\n});";
foo();

Both alerts "FOO! again", not "FOO! again more".


回答1:


What they wanted to highlight is that the JS parser needs to its work every single time the Function constructor is called - basically just the obvious. There is no caching of the passed code string involved.

This is relevant [only] when compared with closures. Suppose we have these two functions:

function makeAlerterParse(string) {
    return Function("alert("+JSON.stringify(string)+");");
}
function makeAlerterClosure(string) {
    return function alerter() { alert(string); };
}

Both function declarations will be parsed when the script is loaded - no surprises. However, in the closure also the alerter function expression is parsed already. Let's make some alerters:

var alerter1 = makeAlerterParser("1"); // Here the parser will be invoked
alerter1(); // no parsing, the function is instantiated already and 
alerter1(); // can be interpreted again and again.

var alerter2 = makeAlerterClosure("2"); // Here, no parser invocation -
alerter2(); // it's just a closure whose code was already known
alerter2(); // but that has now a special scope containing the "2" string

Still no surprise? Good, then you have already understood everything. The warning is only that an explicit invocation like

for (var fnarr=[], i=0; i<100; i++)
    fnarr[i] = makeAlerterParse(i);

will really be 100 invocations of the JS parser, while the closure version comes for free.




回答2:


My understanding is that with a function constructor, the engine stores the body string as a string rather than as the function it creates; thus, it would need to be reparsed (converted from a string to a function) every time you use it.

Whereas a function declaration or expression parses it the first time, and stores it in memory as a function, so whenever you use it, it goes to the memory location of the function to access it.

If we look at your example, I think it could be read like this:

var bar = 'FOO!';
var foo = (new Function("return(function() {\n\talert(bar);\n});"))();
// function() {\n\talert(bar);\n} is a function declaration, so when it's evaluated
// the first time, the engine pulls out the function and stores it as an anonymous function

bar = 'FOO! again';
foo(); //The segment "function() {\n\talert(bar);\n}" of the function body string is not re-parsed.

'FOO! again' is the expected output since the function just references the variable bar, so once the foo is constructed, it just points to the variable as opposed to taking its value.

I think foo would be stored something like this:

"return function_location"

Which would get parsed every time it's executed.

In your last example, it doesn't alert 'FOO! again more' because when you used the constructor, it saved it as a string rather than a pointer to the variable. But what's interesting about your last example is that it stores the outer variable as a string, yet keeps the inner variable as it is.



来源:https://stackoverflow.com/questions/20695573/js-function-constructor-re-parsed-everytime

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!