测试变量是否在包含范围中声明

时间:2018-11-11 20:48:39

标签: javascript typeof

我有一个内部函数,该函数引用一个由其包含的外部函数初始化的变量:

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';
};

编辑:我现在了解到,此行为是由letconst变量discussed elsewhere引起的“时间盲区”的结果。但是,我仍在寻找一种干净,安全的方式来处理这种情况。

是否有任何安全的方法来测试块范围变量(例如,使用“ let”或“ const”创建的变量)是否已声明?

2 个答案:

答案 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();
};