为什么在我的函数中,eval()内的typeof会抛出一个错误?

10

我尝试实现一个类似于angular.isDefined(...)的函数,但允许检查变量及其属性,因此我编写了这个概念验证:

function check(s) {
  let parts = s.split('\.');
  let partial = '';

  return parts.every(p => { 
    partial += (partial ? '.': '') + p;
    let expr = `typeof ${partial}`;
    console.log('Evaluating', expr);
    return eval(expr) !== 'undefined';
  });
}

check('obj');
let obj={};
check('obj');
obj.a=1;
check('obj.a');

我知道typeof可以用于未声明的标识符,并且它似乎在eval()内正常工作:

console.log(typeof someVariableWhichDoesNotExists)
console.log(eval('typeof someVariableWhichDoesNotExists'));

但是当我的代码被 eval() 处理时失败了。我漏掉了什么?

PS:我读过为什么 typeof 有时会抛出 ReferenceError?,但我认为这不是同样的情况,因为我这里并没有检查表达式,而只是一个标识符。


1
这真的很有趣。这里有一个更小的重现代码:eval('typeof obj'); let obj;。这会抛出一个ReferenceError,但是如果你移除let obj,错误就会消失,而且eval返回了预期的'undefined'。将let obj移到eval之前也可以让错误消失,这让我想到这可能与变量提升有关。 - Jordan Running
1
@JordanRunning 如果你把 let 改成 var,代码就能按预期工作。非常有趣。 - Mathyn
1个回答

10

实际上这与 eval() 无关。你的错误是因为在定义let obj之后却试图在它被定义之前使用它。这个异常在此处描述:

但随着块级作用域变量 let 和 const 的添加,在块中对 let 和 const 变量(或类)使用 typeof 在它们声明之前将抛出 ReferenceError。块级作用域变量从块开始就处于“暂时性死区”,直到初始化被处理期间,如果访问它们则会抛出错误。

不使用 eval(),也可以轻松地导致此错误:

// undefined no problem because obj was not declared
console.log(typeof obj)

// undefined but variable declared with let
// but not defined before using it results in an error
console.log(typeof otherobj)
let otherobj = {}

如果您删除let obj = {};声明或使用var obj = {},您的错误将消失。


4
关于 let 的问题,Mozilla 网站有一篇关于暂时性死区的文档,非常有用。我建议您参考此文档以获取更多信息。 - DKyleo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接