我有一个内部函数,该函数引用一个由其包含的外部函数初始化的变量:
function outer() {
function inner() {
if (foo) { ... }
}
let foo = 'bar';
inner(); // no error
};
但是,在某些情况下,可以在定义foo
的语句执行之前 调用内部函数。在这种情况下,对foo
的任何引用都会在内部函数中引起ReferenceError:
function outer() {
function inner() {
if (foo) { ... } // ReferenceError: foo is not defined
}
inner();
let foo = 'bar';
};
考虑到foo
具有块作用域,并且在执行内部函数时我位于封闭的块中,这使我感到惊讶。
更令人惊讶的是,即使尝试使用typeof
运算符检测这种情况-我一直认为这是测试未定义变量的安全方法-也会导致相同的ReferenceError:
function outer() {
function inner() {
if (typeof foo !== 'undefined') { ... } // ReferenceError: foo is not defined
}
inner();
let foo = 'bar';
};
编辑:我现在了解到,此行为是由let
和const
变量discussed elsewhere引起的“时间盲区”的结果。但是,我仍在寻找一种干净,安全的方式来处理这种情况。
是否有任何安全的方法来测试块范围变量(例如,使用“ let”或“ const”创建的变量)是否已声明?
答案 0 :(得分:2)
一种蛮力方法是在初始化typeof
之前,简单地捕获foo
在“临时死区”中抛出的异常:
function outer() {
function inner() {
let fooExists = false;
try { fooExists = typeof foo !== 'undefined' } catch(e) {}
if (fooExists) { /* ... */ }
}
inner(); // no error
let foo = 'bar';
}
也可以使用var
代替let
来解决此问题。因为var
是函数作用域的,所以声明将被提升到outer
的顶部,从而使变量在外部执行时始终可用(尽管未定义):
function outer() {
// due to hoisting, there is a logical `var foo;` here
function inner() {
if (typeof foo !== 'undefined') { /* ... */ }
}
inner(); // no error; `foo` has been hoisted
var foo = 'bar';
}
可以通过将foo
的声明(而不是初始化)放在外部函数的顶部,同时仍使用let
来采取类似的方法:
function outer() {
let foo;
function inner() {
if (typeof foo !== 'undefined') { /* ... */ }
}
inner(); // no error
foo = 'bar';
}
对于问题中给出的示例,最后一个解决方案似乎是最干净的解决方案。不幸的是,使用const
变量时不能使用它。
答案 1 :(得分:-1)
function outer() { function inner() { if (foo) { ... } // ReferenceError: foo is not defined } inner(); let foo = 'bar'; };
这让我感到惊讶,因为foo具有块作用域,而我 在执行内部函数时,将其包含在封闭块中。
由于吊起,foo
的 声明 被吊起在块的顶部,而不是 初始化em> 。它的执行就像您写过一样:
function outer() {
let foo; // declaration only, so still undefined value
function inner() {
if (foo) { ... } // ReferenceError: foo is not defined
}
inner();
foo = 'bar'; // Not initialized until after you call inner!
};
只需在块中向上移动初始化即可,
function outer() {
let foo = 'bar'; // declared and initialized
function inner() {
if (foo) { ... } // works as expected
}
inner();
};