专栏名称: 程序员大咖
为程序员提供最优质的博文、最精彩的讨论、最实用的开发资源;提供最新最全的编程学习资料:PHP、Objective-C、Java、Swift、C/C++函数库、.NET Framework类库、J2SE API等等。并不定期奉送各种福利。
目录
相关文章推荐
逸言  ·  怎么看待AI辅助编程 ·  2 天前  
51CTO官微  ·  端午假期即将到来,让我看看是谁还没下班 ·  3 天前  
51好读  ›  专栏  ›  程序员大咖

从 JavaScript 作用域说开去

程序员大咖  · 公众号  · 程序员  · 2017-06-03 19:34

正文

请到「今天看啥」查看全文


JavaScript 中变量的作用域


大多数的主流语言都是有块级作用域的,变量在最近的代码块中,Objective-C 和 Swift 都是块级作用域的。但是在 JavaScript 中的变量是函数级作用域的。不过在最新的 ES6 中加入了 let 和 const 关键字以后,就变相支持了块级作用域。到了 ES6 以后支持块级作用域的有以下几个:


with 语句


用 with 从对象中创建出的作用域仅在 with 声明中而非外 部作用域中有效。


try/catch 语句


JavaScript 的 ES3 规范中规定 try/catch 的 catch 分句会创建一个块作用域,其中声明的变量仅在 catch 内部有效。


let 关键字


let关键字可以将变量绑定到所在的任意作用域中(通常是{ .. }内部)。换句话说,let 为其声明的变量隐式地了所在的块作用域。


const 关键字


除了 let 以外,ES6 还引入了 const,同样可以用来创建块作用域变量,但其值是固定的 (常量)。之后任何试图修改值的操作都会引起错误。


这里就需要注意变量和函数提升的问题了,这个问题在前一篇文章里面详细的说过了,这里不再赘述了。


不过这里还有一个坑,如果赋值给了一个未定义的变量,会产生一个全局变量。


在非严格模式下,不通过 var 关键字直接给一个变量赋值,会产生一个全局的变量


function func() { x = 123; }

func();

x

<123


不过在严格模式下,这里会直接报错。


function func() { 'use strict'; x = 123; }

func();


在 ES5 中,经常会通过引入一个新的作用域来限制变量的生命周期,通过 IIFE(Immediately-invoked function expression,立即执行的函数表达式)来引入新的作用域。


通过 IIFE ,我们可以


  • 避免全局变量,隐藏全局作用域的变量。

  • 创建新的环境,避免共享。

  • 保持全局的数据对于构造器的数据相对独立。

  • 将全局的数据附加到单例对象上。

  • 将全局数据附加到方法中。

JavaScript 欺骗作用域


(1). with 语句


with 语句被很多人都认为是 JavaScript 里面的糟粕( Bad Parts )。起初它被设计出来的目的是好的,但是它导致的问题多于它解决的问题。


with 起初设计出来是为了避免冗余的对象调用。


举个例子:


foo.a.b.c = 888;

foo.a.b.d = 'halfrost';


这时候用 with 语句就可以缩短调用:


with (foo.a.b) {

c = 888;

d = 'halfrost';

}


但是这种特性却带来了很多问题:


function myLog( errorMsg , parameters) {

with (parameters) {

console.log('errorMsg:' + errorMsg);

}

}


myLog('error',{});


myLog('error',{ errorMsg:'stackoverflow' });


可以看到输出就出现问题了,由于 with 语句,覆盖掉了第一个入参。通过阅读代码,有时候是不能分辨出这些问题,它也会随着程序的运行,导致发生不多的变化,这种对未来的不确定性就很容易出现

bug。


with 会导致3个问题:


  • 性能问题

变量查找会变慢,因为对象是临时性的插入到作用域链中的。


  • 代码不确定性

@Brendan Eich 解释,废弃 with 的根本原因不是因为性能问题,原因是因为“with 可能会违背当前的代码上下文,使得程序的解析(例如安全性)变得困难而繁琐”。


  • 代码压缩工具不会压缩 with 语句中的变量名


所以在严格模式下,已经严格禁止使用 with 语句。


Uncaught SyntaxError: Strict mode code may not include a with statement


如果还是想避免使用 with 语句,有两种方法:


  1. 用一个临时变量替代传进 with 语句的对象。

  2. 如果不想引入临时变量,可以使用 IIFE 。


(function () {

var a = foo.a.b;

console.log('Hello' + a.c + a.d);

}());


或者


(function (bar) {

console.log('Hello' + bar.c + bar.d);

}(foo.a.b));


(2). eval 函数


eval 函数传递一个字符串给 JavaScript 编译器,并且执行其结果。







请到「今天看啥」查看全文