本系列文章为You Don't Know JS的读书笔记。
书籍地址:https://github.com/getify/You-Dont-Know-JSgit
一个很是广泛的观点是,Javascript的做用域是基于函数的,这个观点其实并非那么正确,不过,让咱们来先看一下函数级别的做用域。github
function foo(a) { var b = 2; // some code function bar() { // ... } // more code var c = 3; }
foo函数中有4个标识符,a、b、c、bar。这些标识符在什么位置定义并不重要,变量或者是函数,都将归属于当前的做用域。
bar()也有与之对应的做用域,全局做用域也是如此(仅有一个表示符foo与它关联)。
a,b,c,bar都隶属于foo(..)做用域,在foo(..)的外部,是没法操做到它们的。在全局做用域下写以下代码:会抛出ReferenceErrorexpress
bar(); // fails console.log( a, b, c ); // all 3 fail
使用函数做为代码的封装,有一些细节上的问题:咱们使用foo(..)封装代码时,foo自己也污染了做用域。若是咱们只是为了隐藏细节,不是为了抽象代码逻辑,那么,这是一个解决方案:函数
(function foo(){ // Coding here })();
这样作,foo是污染不了全局做用域的(也许咱们更愿意在这种状况下采用匿名版本)。工具
(function (){ // Coding here })();
这里说一下使用匿名函数的两个坏处:没法在stack traces中识别到他们、低代码可读性。
因此除了较短的逻辑,尽可能不要用匿名函数。code
刚才咱们经过把函数包装在(..)中,再当即调用,被称为Immediately Invoked Function Expression,简称为IIFE,为了不匿名函数的坏处,IIFE能够这样命名ip
var a = 2; (function IIFE(){ var a = 3; console.log( a ); // 3 })(); console.log( a ); // 2
关于客户端的IIEF,常常能够看到这样的代码,传window,作些事情。作用域
var a = 2; (function IIFE( global ){ var a = 3; console.log( a ); // 3 console.log( global.a ); // 2 })( window );
还有这样的,比较暗黑的作法(防止某变量被外界覆盖,好比undefined):get
undefined = true; // setting a land-mine for other code! avoid! (function IIFE( undefined ){ var a; if (a === undefined) { console.log( "Undefined is safe here!" ); } })();
for (var i=0; i<10; i++) { console.log( i ); } console.log(i);
不少从其它语言切换切换到js,不能理解以上的代码竟然能够输出10。
其它语言经常使用到的块级做用域,在js上彷佛没有,其实否则。
try/catch
it
try { undefined(); // illegal operation to force an exception! } catch (err) { console.log( err ); // works! } console.log( err ); // ReferenceError: `err` not found
注意到没有,catch是能拿到err,可是log却拿不到。
虽然这是ES3的规范,可是不少语法验证工具会在有多个try/catch,且catch的形参都为err或者其它相同的名字时,会报re-definition的warning,不用管。
let
ES6提供了新的关键字let。
var foo = true; if (foo) { let bar = foo * 2; bar = something( bar ); console.log( bar ); } console.log( bar ); // ReferenceError
块级风格。
for (let i=0; i<10; i++) { console.log( i ); } console.log( i ); // ReferenceError
须要注意的是,若是使用let
{ console.log( bar ); // ReferenceError! let bar = 2; }
在这一点上,和var是不同的。
const也是ES6提供的新关键字,除了定义出的变量初始化后不可更改外,其它与let一致。