var foo = function bar(i) {
bar = "change bar reference";
if (i < 5) {
setTimeout(function () {
console.log(i);
bar(++i);
},
1000
);
}
}
以上功能没有错误。
var foo = function bar(i) {
var bar = "change bar reference";
if (i < 5) {
setTimeout(function () {
console.log(i);
bar(++i);
},
1000
);
}
}
将var
添加到bar后,第二个函数出错。
我希望两个函数都抛出异常,而不仅仅是带有var bar
的第二个函数。
我不明白为什么只有第二个函数引发异常。
我得到带有var
的变量声明不会覆盖标识符“ bar”,但是赋值将在运行时执行。我明白为什么var bar是字符串而不是第二个函数上的函数,因此引发异常。
为什么第一个函数不会引发异常? bar显然已分配给字符串。
我读了documentation,发现下面有一些有用的内容。
可以从FunctionExpression的FunctionBody内部引用FunctionExpression中的标识符,以允许该函数以递归方式调用自身。但是,与FunctionDeclaration中的功能不同,FunctionExpression中的Identifier不能从其引用,也不会影响包围FunctionExpression的作用域。
“无法引用FunctionExpression中的标识符”是否意味着我无法在第一个函数中使用bar = "change bar reference";
?
JavaScript脚本引擎看到bar = "change bar reference"
时会做什么?它只是跳过行吗?
编辑:未捕获的TypeError:bar不是函数
foo(1)
答案 0 :(得分:2)
这样做的原因是,根据ES规范,命名函数的名称上存在不可变绑定:
来自Section 14.1.20 of the ES6 spec:
- 让 envRec 成为funcEnv的EnvironmentRecord。
- 让 name 为BindingIdentifier的StringValue。
- 执行envRec.CreateImmutableBinding(name)。
不可变的绑定意味着标识符的值不能被覆盖。此外,尝试以严格模式should produce a runtime error分配给它:
12.14.1:在ECMAScript 2015中,包含对不可变绑定的分配(例如FunctionExpression的函数名称)的严格模式代码不会产生早期错误。而是会产生运行时错误。
观察:
var foo = function bar() {
bar = 2;
console.log(bar);
};
foo();
因此,在第一个示例中,除非严格模式,否则您对bar
的分配实际上没有任何作用。
在第二个示例中,通过在新作用域中声明变量来使bar
标识符 shadowing 。这就是bar
在第二个示例中保留分配值的原因。
var foo = function bar() {
var bar = 2;
console.log(bar);
};
foo();
答案 1 :(得分:1)
至少在调用foo
或bar
时,您会收到错误消息,因为该函数已不存在。
为什么第一个函数没有抛出异常? bar显然已分配给字符串。
在运行时,没有调用该函数,什么也没有发生,但是在调用该函数之后,变量bar
以字符串作为值,而不是用于进一步调用超时的函数。罢工>
这取决于。在Edge上,它只是跳过分配,在Chrome上,它会引发错误
Assignment to constant variable.
这意味着命名函数被实现为const。
var foo = function bar(i) { // <<<---------+
bar = "change bar reference"; // --+ tries to change global bar
if (i < 5) {
setTimeout(
function () {
console.log(i);
bar(++i);
},
1000
);
}
};
foo(0);
我阅读了文档,并在下面得到了一些有用的信息。 “可以从FunctionExpression的FunctionBody内部引用FunctionExpression中的标识符,以允许该函数以递归方式调用其自身。但是,与FunctionDeclaration中的情况不同,FunctionExpression中的Identifier不能从包含该FunctionExpression的范围中进行引用,并且不会对其产生影响。”
是否“无法从FunctionExpression中引用标识符”是否意味着我不能做bar =“更改栏引用”;在第一个功能?
您的问题不清楚。
当JavaScript脚本引擎看到bar =“更改栏引用”时会做什么?它只是跳过行吗?
不。它将值分配给本地bar
或全局bar
,但是如果具有本地或全局变量,则将本地变量用于全局变量。
'use strict';
function foo() {
var a = 'bar';
console.log(a); // bar
}
var a = 42;
foo();
console.log(a); // 42
答案 2 :(得分:0)
让我尝试用简单的词来阐述。 在第一个函数中,您试图修改/重新定义/覆盖不允许的NFE(命名函数表达式)“ bar”。由于您没有使用“严格模式”,因此没有收到运行时错误。万一您将进入严格模式,您将收到“ Uncaught TypeError:Assigning to constant variable”,因为在NFE函数名内部将其视为常量,因此任何人都无法覆盖其值。
在第二个函数中,“ bar”将推断出一个字符串值,这就是为什么它会引发错误,因为几行之后,您就将其用作函数。 我希望这是有道理的。 要仔细检查,我们可以执行以下脚本: 下面的脚本将返回“ function”,然后返回“ bar” function的定义,因为我没有使用严格模式
var foo = function bar() {
console.log(typeof(bar)) ;
bar = "new definition"; // try to redefine
console.log( bar );
};