删除非限定标识符时出现严格模式语法错误背后的动机

Motive behind strict mode syntax error when deleting an unqualified identifier?

本文关键字:语法 模式 错误 背后 动机 标识符 删除      更新时间:2023-09-26

我很难理解为什么在严格模式下,当delete用于非限定标识符时会发生语法错误。

在大多数情况下,这是有道理的...如果您使用 var 关键字以通常的方式声明变量,然后尝试对它们使用 delete,则在非严格模式下,它将静默失败,因此在这些情况下,严格模式失败并显示错误是有意义的。

但是,在某些情况下,您无法删除符合条件的标识符:

(function() {
  // "use strict";
  var obj = Object.create({}, { bloop: { configurable: false } });
  delete obj.bloop; // throws TypeError in strict mode, silently fails in non-strict.
  console.log('bloop' in obj); // true
}());

严格模式必须在此处执行运行时检查,因为遇到此问题时会引发 TypeError。在某些情况下,您可以在非严格模式下成功删除非限定标识符...

// "use strict";
window.bar = 6;
console.log(typeof bar); // number
delete bar; // works in non-strict, syntax error in strict!
console.log(typeof bar); // undefined

事实上,据我了解,是否可以删除内容(在非严格模式下(取决于内部[[Configurable]]属性,与限定标识符无关。据我所知,在严格模式下无法删除可配置的非全局变量(作为本地 VO 的属性(:

(function() {
  // "use strict";
  eval('var foo = 5;');
  console.log(typeof foo); // number
  delete foo; // works in non-strict, SyntaxError in strict.
  console.log(typeof foo); // undefined
}());

所以,我的问题是,当对非限定标识符使用 delete 时抛出 SyntaxError 有什么意义,如果属性不可配置,TypeError 无论如何都会抛出?这似乎是一个不必要的限制,在某些情况下,除了不使用严格模式(第三个示例(之外,似乎没有任何解决方法。谁能解释一下这个决定背后的动机?


更新:我刚刚意识到我忽略了这样一个事实,即直接eval调用在严格模式下有自己的作用域,而不是调用函数的作用域,因此在第三个示例中,foo不会在严格模式下定义。无论如何,运行时检查仍然会捕获这一点,但它提出了一个附带问题:是否没有办法在严格模式下拥有可配置的局部变量,就像我们在非严格模式下对eval变量声明所做的那样?AFAIK是eval为数不多的合法用途之一。

您正在谈论规范的第 11.4.1 节第 5.a 段:

  1. 否则,ref 是对环境记录绑定的引用,因此
    一个。如果 IsStrictReference(ref( 为 true,则抛出 SyntaxError 异常。
    b.让绑定是 GetBase(ref(。
    c.返回调用绑定的 DeleteBinding 具体方法的结果,提供 GetReferencedName(ref( 作为参数。

您所谓的"非限定标识符"正式命名为"环境记录绑定"。

现在,回答你的问题。当 5.c. 无论如何都会失败时,为什么要抛出 SyntaxError?我想你自己回答了!

严格模式必须在此处执行运行时检查,因为遇到此问题时会引发 TypeError。

没错。但快速失败总是更好。因此,当有机会检测到 SyntaxError 时(在解析时(,应该抓住这个机会。

为什么?如果发生错误,它省去了修复应用程序的麻烦。考虑一下可能会立即显示错误的 IDE,而不是数小时的调试。
此外,此类限制可能对优化的 JIT 编译器有利。

如果要在严格模式下删除对象。您必须明确提及属性访问权限。另请注意,如何调用函数很重要。如果不使用运算符newthisuse strict 下未定义,并且不能使用以下方法。例:

"使用严格"函数 func(({  var self = this;  self.obj = {};  self.obj.x = 'y'  console.log(self.obj(;  删除自我.obj//作品  删除 obj//不起作用  console.log(self.obj(;}var f = new func((;

要删除函数(闭包(之外的对象,您必须像

与上述代码相同删除 F.obj