Javascript 每次重新解析JS函数构造函数?

Javascript 每次重新解析JS函数构造函数?,javascript,performance,function,parsing,function-constructor,Javascript,Performance,Function,Parsing,Function Constructor,在MDN中,关于每次求值时解析的是什么意思?这可以通过代码来观察吗 函数构造函数与函数声明与函数表达式一节中的引用: 由函数表达式和函数声明定义的函数只解析一次,而由函数构造函数定义的函数不解析一次。也就是说,每次计算传递给函数构造函数的函数体字符串时,必须对其进行分析。尽管函数表达式每次都创建闭包,但函数体未重新解析,因此函数表达式仍然比“新函数(…)”更快。因此,应尽可能避免使用函数构造函数。 但是,应该注意,通过解析函数构造函数的字符串生成的函数中嵌套的函数表达式和函数声明不会重复解析。例

在MDN中,关于每次求值时解析的是什么意思?这可以通过代码来观察吗

函数构造函数与函数声明与函数表达式一节中的引用:

由函数表达式和函数声明定义的函数只解析一次,而由函数构造函数定义的函数不解析一次。也就是说,每次计算传递给函数构造函数的函数体字符串时,必须对其进行分析。尽管函数表达式每次都创建闭包,但函数体未重新解析,因此函数表达式仍然比“新函数(…)”更快。因此,应尽可能避免使用函数构造函数。 但是,应该注意,通过解析函数构造函数的字符串生成的函数中嵌套的函数表达式和函数声明不会重复解析。例如:
var foo=(新函数(“var bar=\'foo!\';\n返回(函数(){\n\talert(bar);\n});”)()
foo()//函数体字符串的段“function(){\n\talert(bar);\n}”未重新分析。

我编写了一段代码片段来测试和理解它:

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();
这两个都会提醒“再次版本”

重新解析的是什么意思

这可以用代码结果来说明吗

谢谢


仅供参考,我尝试了另一个代码片段:

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();

这两个警报都是“FOO!再次”、而不是“FOO!再次更多”

我的理解是,对于函数构造函数,引擎将主体字符串存储为字符串,而不是它创建的函数;因此,每次使用它时都需要重新解析(从字符串转换为函数)

而函数声明或表达式第一次解析它,并将其作为函数存储在内存中,因此无论何时使用它,它都会转到函数的内存位置来访问它

如果我们看看你的例子,我认为可以这样理解:

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.
"return function_location"
“福!“再次”是预期的输出,因为函数只引用变量
bar
,因此一旦构建
foo
,它只指向变量,而不是取其值

我认为
foo
将存储如下内容:

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.
"return function_location"
每次执行时都会被解析


在上一个示例中,它不会提醒“FOO!”!再次强调“更多”,因为当您使用构造函数时,它将其保存为字符串,而不是指向变量的指针。但上一个示例的有趣之处在于,它将外部变量存储为字符串,而将内部变量保持原样。

他们想强调的是,每次调用
函数
构造函数时,JS解析器都需要工作—基本上是显而易见的。没有缓存所传递的代码字符串

与闭包相比,这[仅]是相关的。假设我们有两个函数:

function makeAlerterParse(string) {
    return Function("alert("+JSON.stringify(string)+");");
}
function makeAlerterClosure(string) {
    return function alerter() { alert(string); };
}
这两个函数声明都将在加载脚本时被解析——这并不奇怪。但是,在闭包中,
警报
函数表达式也已被解析。让我们制作一些警报:

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
还是不奇怪?很好,那么你已经明白了一切。警告只是一个显式调用,如

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

for(var fnarr=[],i=0;i计算变量
bar
与解析表达式不同。我认为所做的区别只会影响性能,而不会影响代码的效果。感谢@Barmar,我也认为这主要是性能问题。但据我所知,重新解析就像重新读取(或重新编译)一样代码。因此,如果在每次解析之间对代码进行更改,在某些情况下,它应该能够反映在结果中。当然,但这是一个不同的函数构造函数。他们所说的是,即使传递给
函数
构造函数的参数与以前的字符串相同,它们也将被重新指定谢谢你的回答,并试图解释细节。
返回函数位置+1
。是的,在最后一个示例中,函数构造函数实际上复制了字符串,这很有趣。我认为这是一个很难真正理解和解释的问题。您需要V8或SpiderMonkey团队的人的耳朵……不,它不是每次使用时都被解析的。解析可能会延迟到第一次调用(作为优化),但每个
函数()只运行一个解析器
call.@Bergi:你有关于函数只被解析一次的参考吗?@Marc:还没有,你可以在js引擎的源代码中查找它。这对用户没有任何影响;如果只需要解析一次,为什么会被多次解析呢?谢谢@Bergi。你是说在“闭包版本”中,
函数警报()
已经过预处理(预解析),这就像该函数已经在作用域的顶部定义(并编译)了一样?但函数构造函数不会(很可能不会)移动到顶部,就像普通语句一样,每次遇到它都需要运行。如果您可以包含一个具有不同可见结果的示例,那将非常好!是的,闭包不需要任何额外的解析步骤-它可以在读入脚本时编译。执行
makeAlerterClosure
将t创建具有不同范围内容的函数对象,但这些对象共享(一次)编译代码。事实上,函数构造函数是一个普通的表达式,我们每次遇到它时都需要运行解析器。不,我不能包含一个不同行为的示例,因为它们在功能上是等效的。
函数
构造函数效率很低,不应该用于此目的。