在Javascript中,何时创建新范围?(使用新功能和"with"语句)这些只是两种情况吗?

nop*_*ole 18 javascript closures scope

在Javascript中,何时创建新范围?我知道的两种情况是:

  1. 使用新功能(2012/09 更新,我认为它需要是函数调用,而不仅仅是函数定义)
  2. 在"with"声明中

作为一个注释,任何新的块(在if-then-else,循环,或者只是因为其他原因开始一个块)都不会创建一个新的范围.

是否存在第三种情况,除了上述两种情况之外还会创建新范围?谢谢.

CMS*_*CMS 9

是的,第三种情况是扩展范围链(除了Shog9提到的letmozilla扩展),当评估一个块时:catch

生产Catch:catch(Identifier)Block的计算方法如下:

  1. 设C是已传递给此生产的参数.

  2. 像表达式new Object()一样创建一个新对象.

  3. 在对象Result(2)中创建一个属性.该属性的名称是Identifier,valueisC.值和属性是{DontDelete}.

  4. 将结果(2)添加到范围链的前面.

  5. 评估阻止.

  6. 作用域链的前面删除结果(2).

  7. 返回结果(5).

基本上,创建一个新对象,其中一个名为Identifier的属性被传递给catch,这个新对象被添加到作用域链中,因此我们可以在catch块中使用该标识符.

try {
  throw "error";
} catch (identifier) {
  // `identifier` accessible here..
}
Run Code Online (Sandbox Code Playgroud)

但请记住,它只是暂时增加当前范围,引入catch标识符,内部声明的任何变量将被简单地提升到其封闭函数的顶部.


Sho*_*og9 6

还有let语句.请记住let (...) {},喜欢with (...){},不创建变量引入一个新的范围的块.但是,定义 可以创建作用于它们定义的块(任何块)的变量.

公平警告:正如评论中指出的那样,虽然它let是JavaScript 1.7(ECMA-262/ECMAScript的Mozilla方言)的一部分,但它不是 ECMAScript的一部分,并且可能不会很快在除Firefox之外的浏览器中工作.另请注意,虽然with可以在ECMAScript的当前实现中用作let语句的替代,但针对挂起的ECMA-262第5版提出的"严格"模式也不允许这样做.如果您担心编写跨平台,面向未来的代码(您应该......),那么请坚持使用范围控制功能!

  • @Andy没有被广泛实现,因为它是*Mozilla Extension*仅在SpiderMonkey和Rhino引擎上可用,并且不是ECMAScript标准的一部分. (2认同)