删除非限定标识符时,严格模式语法错误背后的动机是什么?

时间:2012-05-17 21:10:32

标签: javascript ecmascript-5

我无法理解为什么在严格模式下,当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的少数合法用途之一。

2 个答案:

答案 0 :(得分:6)

您正在谈论规范的Section 11.4.1, paragraph 5.a.

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

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

现在,问你的问题。为什么在5.c.时抛出一个SyntaxError。反正会失败吗?我想你自己回答了!

  

严格模式必须在此执行运行时检查,因为遇到此情况时会抛出

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

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

答案 1 :(得分:2)

如果要在严格模式下删除对象。您必须明确提及有关属性访问权限。另请注意,您如何调用该函数非常重要。如果new运算符未被使用thisuse strict下未定义,则您无法使用以下方法。 例如:

'use strict'
function func(){
  var self = this;
  self.obj = {};
  self.obj.x = 'y'

  console.log(self.obj);
  delete self.obj // works
  // delete obj // doesn't work
  console.log(self.obj);
}

var f = new func();

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

// same code as above
delete f.obj