- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
function f1(x = 2, f = function() {x = 3;}) {
let x = 5;
f();
console.log(x);
}
f1();
在这段代码中有一个语法错误表明Identifier 'x' has already been declared
。很明显,我们不能在一个范围内使用 let
重新声明一个变量。但我不知道为什么在这段代码中我们仍然会收到此错误,因为在 ES6 中默认参数实际上会创建另一个名为参数环境的范围。
http://www.ecma-international.org/ecma-262/6.0/#sec-functiondeclarationinstantiation
If the function’s formal parameters do not include any default value initializers then the body declarations are instantiated in the same Environment Record as the parameters. If default value parameter initializers exist, a second Environment Record is created for the body declarations. Formal parameters and functions are initialized as part of FunctionDeclarationInstantiation. All other bindings are initialized during evaluation of the function body.
所以这里我们有一个全局作用域、一个参数作用域和一个函数作用域。在参数范围内,我们声明了一个名为 x
的参数,同时我们还在函数范围内声明了另一个名为 x
的变量。尽管这两个名称相同,但它们存在于不同的范围内。为什么在这种情况下我们仍然会收到提示不允许重复的语法错误?
最佳答案
是的,你是对的。这里涉及三个不同的范围(一个用于第一个参数,一个用于第二个,一个用于主体)。
然而,在参数被初始化(在它们自己的范围内)之后,它们被复制到一个新的词法环境(然后主体将在其中执行)(可以在规范的 9.2.15 中找到)。
这意味着参数名称不仅存在于参数的范围内,而且还存在于计算主体的范围内,因此在主体内使用相同的名称是 重新声明变量,导致错误(使用 let
/const
)。
这是规范的演练:
当一个函数被解析时,它会创建一个函数对象,其中包含一些内部属性:
[[Environment]]:这是对外部作用域的引用,因此您可以在函数内部访问外部作用域的变量(这也会导致关闭行为,[[Environment]] 可能会引用一个不是活跃了)。
[[FormalParameters]]:参数的解析代码。
[[ECMAScriptCode]]: 函数体代码。
现在当你调用一个函数时(9.2.1 [[Call]]),它会在调用栈上分配一个环境记录,然后将
Let result be OrdinaryCallEvaluateBody(F, argumentsList).
调用函数。这就是 9.2.15 的用武之地。首先,它将在函数体环境中声明所有参数:
[Initialize local helper variables]
21. For each String paramName in parameterNames, do
i. Perform ! envRec.CreateMutableBinding(paramName, false).
[Rules for initializing the special "arguments" variable]
然后它将初始化所有参数。参数真的很复杂,因为还有rest参数。因此必须迭代参数才能将它们变成数组:
24. Let iteratorRecord be CreateListIteratorRecord(argumentsList)
25. If hasDuplicates is true, then
a. Perform ? IteratorBindingInitialization for formals with iteratorRecord and undefined as arguments.
26. Else,
a. Perform ? IteratorBindingInitialization for formals with iteratorRecord and env as arguments.
现在 IteratorBindingInitialization
在 13.3.3.8 中定义:
它基本上会评估默认值,并会在当前环境中初始化绑定(bind)。
当所有参数都初始化后,函数体的环境就可以准备好了。正如您引用的评论中提到的,如果没有参数初始值设定项,则不需要新的环境。但是,如果某处存在默认值,则会创建一个新环境。
27. If hasParameterExpressions is false, then
[...]
28. Else,
a. NOTE: A separate Environment Record is needed
to ensure that closures created by expressions in the
formal parameter list do not have visibility of
declarations in the function body.
然后创建一个“新范围”,在其中对主体进行评估:
b. Let varEnv be NewDeclarativeEnvironment(env).
c. Let varEnvRec be varEnv's EnvironmentRecord.
d. Set the VariableEnvironment of calleeContext to varEnv.
然后函数的所有变量和参数都在该范围内声明和初始化,这意味着所有参数都被复制:
f. For each n in varNames, do
2. Perform ! varEnvRec.CreateMutableBinding(n, false).
3. If n is [a regular variable declared with "var"], let
initialValue be undefined.
4. Else, [if it is a parameter]
a. Let initialValue be ! envRec.GetBindingValue(n, false)
5. Call varEnvRec.InitializeBinding(n, initialValue).
[Other rules for functions in strict mode]
31. [varEnv gets renamed to lexEnv for some reason]
之后,声明了所有带有 let
/const
的内部变量(但未初始化,它们将在到达 let
时被初始化).
34. Let lexDeclarations be the LexicallyScopedDeclarations of code.
35. For each element d in lexDeclarations, do
a. NOTE: A lexically declared name cannot be the
same as a function/generator declaration, formal
parameter, or a var name. Lexically declared
names are only instantiated here but not initialized.
b. For each element dn of the BoundNames of d, do
i. If IsConstantDeclaration of d is true, then
1. Perform ! lexEnvRec.CreateImmutableBinding(dn, true).
ii. Else,
1. Perform ! lexEnvRec.CreateMutableBinding(dn, false).
现在如您所见,CreateMutableBinding
在这里被调用,并且如 8.1.1.1.2 中所指定...
The concrete Environment Record method CreateMutableBinding for declarative Environment Records creates a new mutable binding for the name N that is uninitialized. A binding must not already exist in this Environment Record.
因为参数已经被复制到当前环境中,调用同名的CreateMutableBinding
将失败。
关于javascript - 为什么即使我在 2 个不同的范围内声明变量仍然存在重复错误?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56301703/
我有 table 像这样 -------------------------------------------- id size title priority
我的应用在不同的 Activity (4 个 Activity )中仅包含横幅广告。所以我的疑问是, 我可以对所有横幅广告使用一个广告单元 ID 吗? 或者 每个 Activity 使用不同的广告单元
我有任意(但统一)数字列表的任意列表。 (它们是 n 空间中 bin 的边界坐标,我想绘制其角,但这并不重要。)我想生成所有可能组合的列表。所以:[[1,2], [3,4],[5,6]] 产生 [[1
我刚刚在学校开始学习 Java,正在尝试自定义控件和图形。我目前正在研究图案锁,一开始一切都很好,但突然间它绘制不正确。我确实更改了一些代码,但是当我看到错误时,我立即将其更改回来(撤消,ftw),但
在获取 Distinct 的 Count 时,我在使用 Group By With Rollup 时遇到了一个小问题。 问题是 Rollup 摘要只是所有分组中 Distinct 值的总数,而不是所有
这不起作用: select count(distinct colA, colB) from mytable 我知道我可以通过双选来简单地解决这个问题。 select count(*) from (
这个问题在这里已经有了答案: JavaScript regex whitespace characters (5 个回答) 2年前关闭。 你能解释一下为什么我会得到 false比较 text ===
这个问题已经有答案了: 奥 git _a (56 个回答) 已关闭 9 年前。 我被要求用 Javascript 编写一个函数 sortByFoo 来正确响应此测试: // Does not cras
所以,我不得不说,SQL 是迄今为止我作为开发人员最薄弱的一面。也许我想要完成的事情很简单。我有这样的东西(这不是真正的模型,但为了使其易于理解而不浪费太多时间解释它,我想出了一个完全模仿我必须使用的
这个问题在这里已经有了答案: How does the "this" keyword work? (22 个回答) 3年前关闭。 简而言之:为什么在使用 Objects 时,直接调用的函数和通过引用传
这个问题在这里已经有了答案: 关闭 12 年前。 Possible Duplicate: what is the difference between (.) dot operator and (-
我真的不明白这里发生了什么但是: 当我这样做时: colorIndex += len - stopPos; for(int m = 0; m < len - stopPos; m++) { c
思考 MySQL 中的 Group By 函数的最佳方式是什么? 我正在编写一个 MySQL 查询,通过 ODBC 连接在 Excel 的数据透视表中提取数据,以便用户可以轻松访问数据。 例如,我有:
我想要的SQL是这样的: SELECT week_no, type, SELECT count(distinct user_id) FROM group WHERE pts > 0 FROM bas
商店表: +--+-------+--------+ |id|name |date | +--+-------+--------+ |1 |x |Ma
对于 chrome 和 ff,当涉及到可怕的 ie 时,这个脚本工作完美。有问题 function getY(oElement) { var curtop = 0; if (oElem
我现在无法提供代码,因为我目前正在脑海中研究这个想法并在互联网上四处乱逛。 我了解了进程间通信和使用共享内存在进程之间共享数据(特别是结构)。 但是,在对保存在不同 .c 文件中的程序使用 fork(
我想在用户集合中使用不同的功能。在 mongo shell 中,我可以像下面这样使用: db.users.distinct("name"); 其中名称是用于区分的集合字段。 同样我想要,在 C
List nastava_izvjestaj = new List(); var data_context = new DataEvidencijaDataContext();
我的 Rails 应用程序中有 Ransack 搜索和 Foundation,本地 css 渲染正常,而生产中的同一个应用程序有一个怪癖: 应用程序中的其他内容完全相同。 我在 Chrome 和 Sa
我是一名优秀的程序员,十分优秀!