本系列文章爲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一致。