我在互联网上通过了这个有趣的测验。
<?php
if(!function_exists('ct_nav_left')) {
function ct_nav_left() { ?>
<nav class="left">
<?php wp_nav_menu (
array(
'menu' => "primary-left",
'menu_id' => "ct-menu",
'menu_class' => "ct-menu",
'echo' => true,
'container' => '',
'container_class' => '',
'items_wrap' => '<ul id="ct-menu" class="ct-menu top_left_menu">
<li id="menu-item-1447"><a href="#">Properties</a>
<div class="container">
<div class="sub-menu">
<div class="col-md-3 left_one_menu">
<a href="#">All Properties</a>
<a href="#/">Enquire Now</a>
</div>
<div class="col-md-3 left_two_menu">
echo do_shortcode( "[contact-form-7 id="1234" title="Contact form
1"]" );
</div>
</div>
</div>
</li>
</ul>',
'container_id' => 'nav-left',
'theme_location' => 'primary_left',
'fallback_cb' => false,
'walker' => new
CT_Menu_Class_Walker
)
); ?>
</nav>
<?php }
}
?>
和选择是:
[2,1,1]
[2,undefined,1]
[2,1,2]
[2,undefined,2]
我选择了解决方案2 TBH,基于x已被重新定义,y被声明和定义为没有值的情况,并且f具有不同的作用域,因此获得了全局x内存点而不是函数x内存点。
但是,我在jsbin.com中尝试过
,我发现它是解决方案1,虽然不确定为什么会弄乱函数主体,并从函数主体中删除了console.log((function(x, f = (() => x)){
var x;
var y = x;
x = 2;
return [x, y, f()]
})(1))
,但发现响应更改为#3,这很有意义因为x值发生了变化,因此x和f显示为2,y显示为1,这是全局声明的。
但是我仍然不明白为什么它显示1而不是未定义。
答案 0 :(得分:23)
但是我仍然不明白为什么它显示1而不是未定义。
不只是你。这是规范的深层部分。 :-)
这里的关键是有两个x
。对真的。有参数 x
,还有变量 x
。
包含表达式的参数列表(如f
的默认值)的自已范围与函数主体的范围分开。但是在参数列表可能包含表达式之前,在具有var x
参数的函数中包含x
无效(x
仍然是参数,具有参数的值)。因此,为了保留它,当其中有一个带有表达式的参数列表时,将创建一个单独的变量,并将该参数的值复制到函数主体开头的变量中。这是看似奇怪 (不,不仅仅是看似)奇怪行为的原因。 (如果您是喜欢介绍规范的人,则此复制为FunctionDeclarationInstantiation的第28步。)
由于f
的默认值() => x
是在参数列表范围内创建的,因此它引用参数 x
,而不是var。
第一个解决方案[2, 1, 1]
是正确的,因为:
2
被分配给函数主体中的变量x
。因此,在函数末尾,变量x
为2
。1
获得值y
之前,将x
从变量x
分配给2
,因此在函数{{1 }}是y
。1
的值从未更改,因此x
在函数结尾处产生f()
就像是 那样,代码是这样写的(我已经删除了不必要的括号并添加了缺少的分号):
1
...我从函数体中删除了var x,发现响应更改为#3 ...
#3是console.log(function(param_x, f = () => param_x) {
var var_x = param_x;
var y = var_x;
var_x = 2;
return [var_x, y, f()];
}(1));
。是正确的,因为当您从函数中删除[2, 1, 2]
时,只有一个var x
这个参数(从参数列表中的函数主体继承)。因此,将x
分配给2
会更改参数的值,x
将返回该值。
以使用f
和param_x
的早期示例为例,如果从其中删除var_x
会是这样:
var x;
这是原始代码的带注释的说明(除去了多余的括号并添加了缺少的分号):
console.log(function(param_x, f = () => param_x) {
var y = param_x;
param_x = 2;
return [param_x, y, f()];
}(1));
关于标题的最后说明:
在IIFE中两次声明变量
变量仅声明一次。另一件事是参数,而不是变量。区别很少重要...这是那些罕见的时期之一。 :-)
答案 1 :(得分:2)
该代码的棘手部分是将=>
函数创建为默认参数值表达式的一部分。在参数默认值表达式中,范围包括在左侧声明的参数,在这种情况下,该参数包括参数x
。因此,出于这个原因,x
函数中的=>
实际上是第一个参数。
仅使用一个参数1
调用该函数,因此,在调用=>
函数时,它返回的结果为[2, 1, 1]
。
正如克劳德先生所指出的那样,var x
声明具有(至少对我来说有点奇怪)在函数范围内制作一个 new x
的效果,将 parameter x
的值复制到其中。没有它,就只有一个(参数)。