15

我无法理解为什么在严格模式下,当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在非严格模式下使用 'd 变量声明一样?AFAIK 是eval.

4

2 回答 2

6

您在谈论第 11.4.1 节第 5.a 段。规格:

  1. 否则, ref 是对环境记录绑定的引用,所以
    a. 如果 IsStrictReference(ref) 为真,则抛出 SyntaxError 异常。
    湾。让绑定为 GetBase(ref)。
    C。返回调用绑定的具体方法 DeleteBinding 的结果,提供 GetReferencedName(ref) 作为参数。

您所说的“不合格标识符”正式命名为“环境记录绑定”。

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

严格模式必须在这里进行运行时检查,因为遇到这种情况时会抛出 TypeError 。

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

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

于 2012-08-19T08:41:32.457 回答
3

如果要在严格模式下删除对象。您必须明确提及属性访问。另请注意,调用函数的方式很重要。If newoperator is not used thisis undefined under use strict,你不能使用下面的方法。例子:

'使用严格'
函数函数(){
  变种自我=这个;
  self.obj = {};
  self.obj.x = 'y'

  控制台.log(self.obj);
  删除 self.obj // 有效
  // 删除 obj // 不起作用
  控制台.log(self.obj);
}

var f = 新函数();

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

// 与上面相同的代码
删除 f.obj
于 2012-08-21T21:12:16.413 回答