JavaScript 中未初始化变量的范围
Scope of uninitialized variable in JavaScript
我不明白为什么这段代码会这样运行:
for (var i = 1; i < 3; i++) {
var j;
if (!j) {
j = 1;
} else {
alert("why are we here? j shouldn't be defined but it's " + j);
}
}
(小提琴)
如果我j
设置为null
并检查null
,它按照我认为的方式工作。
这不是Java,C#,C++等的工作方式,因此令人困惑。
这是因为 JavaScript 中的变量作用域为函数(如果不在函数内,则限定为全局作用域)。var
的作用域不在循环内,大括号不会定义新的闭包。基本上,j
的值在循环体之后仍然存在,并且var
不会将j
重新定义为undefined
。这就是为什么显式设置var j = null;
具有预期效果的原因。
示例 1:
考虑这个问题的一个好方法是,任何时候你用 var
声明一个变量,就像这样。
function someFunc() {
for(var i = 0; i < 3; i++){
var j;
}
}
解释器像这样提升变量声明。
function someFunc() {
var i;
var j;
for(i = 0; i < 3; i++){
}
}
请注意,由于var j
声明被提升到函数的顶部,因此声明实际上在循环中不执行任何操作。
示例 2:
但是,如果您要使用这样的null
初始化变量。
function someFunc() {
for(var i = 0; i < 3; i++){
var j = null;
}
}
会这样解释。
function someFunc() {
var i;
var j;
for(i = 0; i < 3; i++){
j = null;
}
}
请注意,对于每个循环,j
如何设置为 null
。
ES6 let 关键字:
ES6 中有一个关键字,它将在这样的循环中创建一个范围,它是let
关键字。请记住,浏览器对 let
关键字的支持在这一点上很差。
for (var i = 1; i < 3; i++) {
let j;
if (!j) {
j = 1;
} else {
alert("why are we here? j shouldn't be defined but it's "+ j);
}
}
for
循环第一次执行循环主体时,j
未定义,因此代码集j=1
。 在循环的后续迭代中,j
已定义并设置为 1
,因此它按预期进入else
子句。
这是因为在 Javascript 中使用 var
定义的变量是函数作用域的,而不是块作用域的,如果不在函数内,那么它们是全局的。 因此,jsFiddle 中只有一个变量j
,for
循环的每次迭代都使用相同的变量(从而继承了上一次迭代的值)。
如果在 for
循环的主体中初始化j = null;
,它将起作用,因为随后您将为每次迭代重新初始化它,而不是使用上一次迭代中的值。
ES6 建议添加 let
声明,该声明的范围将限定为最接近的块。 请参阅使用"let"和"var"声明变量有什么区别?有关let
的更多信息。
JavaScript 中没有块作用域,只有全局和函数作用域。虽然 JavaScript 变量语句非常灵活,以至于它们会给程序员一种可能存在块作用域的错觉,但事实是,JavaScript 函数中声明的变量稍后由解释器挂起。这意味着它们的声明将移动到最近声明的函数的顶部。举个例子:
function test() {
console.log('a test');
for (var i = 0; i < 100; i++) {
var k = i + Math.random();
console.log(k)
}
}
JavaScript 解释器在内部将代码"转换"为以下内容:
function test() {
var i, k; // var declarations are now here!
console.log('a test');
for (i = 0; i < 100; i++) {
k = i + Math.random();
console.log(k)
}
}
它将把所有var
声明移动到最新函数声明的开头。在您的代码中,吊装将创建以下代码:
// A anonymous function created by jsFiddle to run your script
function () {
var i, j;
for (i = 1; i < 3; i++) {
if (!j) {
j = 1;
} else {
alert("Why are we here? j shouldn't be defined, but it's " + j);
}
}
}
变量在第一次undefined
,然后1
赋值,然后打印您的消息。
- ngDialog-弹出窗口未更新范围变量
- AngularJS范围变量Unwatch
- 将外部控制器的范围变量设置为角度
- 对于使用传递的数据计算的局部范围变量,角度绑定在自定义指令中不起作用
- 如何使用EnquireJS使AngularJS范围变量依赖于媒体查询
- 具有范围变量的控制器不工作
- 范围变量返回长度错误
- 将 NodeJS 模块范围变量作为对象访问
- Angularjs 更新 setTimeout 中的范围变量不起作用
- 递归承诺调用 - 内存范围变量问题
- AngularJS:从指令设置范围变量
- Angularjs:访问范围变量数组并计算平均值
- 范围变量更新,但不更新视图
- 从html调用angularjs控制器中的一个函数,但未定义范围变量
- 如何在编辑范围变量时(暂时)避免摘要循环
- 防止Angular范围变量通过引用自动绑定到服务私有成员
- 使用 AngularJS 从指令设置范围变量
- 集合回调忽略范围变量
- 使用forEach修改角度范围变量
- 因果报应测试中未定义的预期范围变量