# Framework aside ## Global Variable (章節:型別與運算子) ```javascript= // index.html <script src="lib1.js"> <script src="lib2.js"> <script src="app.js"> // lib1.js var libraryName = 'lib1' // lib2.js var libraryName = window.libraryName || 'lib2' // app.js console.log(libraryName) // * 'lib1' ``` `var libraryName = window.libraryName || 'lib2'` 通常框架中會看到類似這行的寫法,用來確認沒有重複使用到相同的變數,若有值則不做事,若非則附值 ## Namespace (章節:物件與函數) A container for variables and functions Typically to keep variables and functions with the same name separate ```javascript= var greet = 'Hello' var greet = 'Hola' console.log(greet) // Hola var english = {} var spanish = {} // english.greetings.greet = 'Hello' // error // just like this => `undefined.greet = 'Hello'` english.greetings = { greet: 'Hello' } // correct way spanish.greet = 'Hola' ``` ## Function Overloading (重載函數) 這邊要講一個很特別的東西,在 JavaScript 沒有的,但其他程式語言有的東西以及為何它不需要重載函數 (function overloading) 在其他的語言 C#、C、JAVA 都有一個叫重載函數的概念,這表示我能讓同一個函數擁有不同數量的參數,但 JavaScript 不行,因為函數就是物件 ```javascript function greet(firstName, lastName, language){ language = language||'English'; if(language === 'English'){ console.log('Hi!'+firstName+' '+lastName); } if(language === 'Spanish'){ cosole.log('Hola!'+firstName+' '+lastName); } } function greetEnglish(firstName, lastName){ greet(firstName, lastName, 'English') } function greetSpanish(firstName, lastName){ greet(firstName, lastName, 'Spanish') } greetEnglish('Amy','Lin'); greetSpanish('John','Chen'); ``` ## 空格 空格,創造空間看不到的字母,舉凡 Enter、Tab、Space,這些可以幫助我們增加程式碼的可讀性,這些東西也不會被程式碼執行。 ```javascript var firstname, lastname, language; var person = { firstname: 'John', lastname: 'Doe' } console.log(person); ``` 那我們可以利用空格這個特性來幫助我們做一些事情,由於 JavaScript 對於空格非常自由,所以我們可以這樣放註解。 ```javascript var // first name of the person firstname, // lastname name of the person lastname, // language is 'es' language; var person = { // the first name firstname: 'John', // the first last lastname: 'Doe' } console.log(person); ``` 從上面範例我們可以瞭解到我們可以在 JavaScript 中很自由的使用空格,所以我們也可以發現這樣做並不會出現錯誤。 最後我們要盡可能善用這個自由特性來撰寫註解,這樣對於我們往後幾年幾個月後回來看這隻程式碼,才能夠盡快理解思緒。 ## IIFEs與安全程式碼 ### 前言 前面我們已經講過 IIFE ,而許多知名框架都會使用到這個技術,所以這章節就要來講講 IIFE 和安全程式碼以及為何它很有用。 ### IIFE 這裡有一個課程提供的範例。 ```javascript // IIFE (function(name) { var greeting = 'Hello'; console.log(greeting + ' ' + name); })('Joun'); ``` 首先讓我們從執行堆來瞭解它做了什麼。 上面是我們正在執行中的 IIFE,而因為我們使用了括號執行了它,創造了一個執行環境。 ![](https://i.imgur.com/UBH8hBn.png) 而這個做法會讓在這裡面的變數,都只會存在於函數內部中,而不是全域環境,所以我們可以試著這樣玩 通常我們要輸出 1…10,都會這樣寫 ↓ ```javascript for(var i = 0 ; i < 10; i++) { console.log(i + 1); } ``` 輸出完畢後我們再看一次目前的 i 會是怎樣 ↓ ```javascript for(var i = 0 ; i < 10; i++) { console.log(i + 1); } console.log(i); ``` ![](https://i.imgur.com/OTnbOUb.png) 可以看到 i 變成 10 了,如果我們預期是這樣子,那就沒有錯,但如果不是呢?我只希望 i 存在於這個迴圈中,那就有問題了,此時就可以使用 IIEF 來解決 ↓ ```javascript (function () { for(var i = 0; i < 10; i++) { console.log( i + 1); } })() console.log(i); ``` ![](https://i.imgur.com/LoUQTP6.png) 所以上面這例子也可以證明,這些變數只會存活於 IIFE 中。 那如果是這樣子的狀況呢? ```javascript var myname = 'Ray'; (function () { for(var i = 0; i < 10; i++) { console.log(i + 1 + myname); } })(); ``` ![](https://i.imgur.com/IZqUBla.png) 可以發現範圍鏈也是可以正常運作的,當然也可以這樣寫 ↓ ```javascript var myname = 'Ray'; (function () { for(var i = 0; i < 10; i++) { var myname = 'Tomy'; console.log(i + 1 + myname); } })(); ``` ![](https://i.imgur.com/oxhU2EW.png) 你可能會說 myname 已經變成 Tomy 了阿! 那我們再加入一行看看目前的 myname ↓ ```javascript var myname = 'Ray'; (function () { for(var i = 0; i < 10; i++) { var myname = 'Tomy'; console.log(i + 1 + myname); } })(); console.log(myname); ``` ![](https://i.imgur.com/dMtIxKK.png) 所以我們可以將程式碼包在 IIFE 中確保它不會和其他東西有衝突甚至污染,你可能會說根本不清楚,那我們這樣寫就會更清楚,知道這種做法是會汙染全域變數 ↓ ```javascript var myname = 'Ray'; for(var i = 0 ; i < 10; i++) { var myname = 'Tomy'; console.log(i + 1 + myname); } console.log(myname); ``` ![](https://i.imgur.com/clEIdnD.png) 課程上也有故意影響全域物件的寫法。 ```javascript var myname = 'Ray'; (function (global) { for(var i = 0; i < 10; i++) { var myname = 'Tomy'; global.myname = myname console.log(i + 1 + myname); } })(window); console.log(myname); ``` ![](https://i.imgur.com/brM2X9l.png) 那這個做法其實就是利用傳參考特性來影響全域物件的寫法。 ## Function Factories ### 前言 在 JavaScript 中閉包有許多好用的地方,所以這堂課將會來講解如何利用閉包來做一些特別特殊的東西甚至是一些看起來不可能的模式。 ### Function Factories 在這邊我們將試著去利用閉包寫出更有威力更有彈性的程式。 ```javascript function makeGreeting (language) { return function (firstname, lastname) { if (language === 'en') { console.log('Hello ' + firstname + ' ' + lastname); }; if (language === 'es') { console.log('Hola ' + firstname + ' ' + lastname); }; }; }; var greetEnglish = makeGreeting('en'); var greetSpanish = makeGreeting('es'); console.log(greetEnglish); console.log(greetSpanish); ``` 由上面範例我們可以看到 greetEnglish、greetSpanish 會指向回傳函數。 ![](https://i.imgur.com/6wl4VtP.png) 但是這邊我們要注意到一件事情 greetEnglish 與 greetSpanish 執行環境的 language 都是獨一無二的,不信?我們可以試著用console.log() 來看。 ```javascript function makeGreeting (language) { console.log(language); return function (firstname, lastname) { if (language === 'en') { console.log('Hello ' + firstname + ' ' + lastname); }; if (language === 'es') { console.log('Hola ' + firstname + ' ' + lastname); }; }; }; var greetEnglish = makeGreeting('en'); var greetSpanish = makeGreeting('es'); console.log(greetEnglish); console.log(greetSpanish); ``` ![](https://i.imgur.com/DMP3v1E.png) 所以我們可以知道,每次執行 makeGreeting 就會產生一個獨一無二的執行環境,那我們也就可以試著去呼叫 greetEnglish 與 greetSpanish。 ```javascript function makeGreeting (language) { return function (firstname, lastname) { if (language === 'en') { console.log('Hello ' + firstname + ' ' + lastname); }; if (language === 'es') { console.log('Hola ' + firstname + ' ' + lastname); }; }; }; var greetEnglish = makeGreeting('en'); var greetSpanish = makeGreeting('es'); greetEnglish('Jack', 'Tom'); greetSpanish('Mary', 'Jude'); ``` 那經過前面的觀念瞭解想必我們已經大概知道結果了。 ![](https://i.imgur.com/HsU2OVB.png) 但是這邊要注意一件事情,我們並沒有辦法直接取用 language 變數,因為這被藏起來在全域環境了,但是函數內是沒有問題的。 讓我們盡可能白話瞭解一下 Function Factories,就是 makeGreeting 類似每一個都是一間房子,然後每一間都有獨立空間,所以我們用圖片來講會更清楚。 ![](https://i.imgur.com/SpFNLvw.png) ###### tags: `WierdJavascript`