// 函式使用外部變數,會使用最新的值嗎?let name ="John";functionsayHi() {alert("Hi, "+ name);}name ="Pete";sayHi(); // what will it show: "John" or "Pete"?// 函式會使用內部變數還是外部變數?functionmakeWorker() {let name ="Pete";returnfunction() {alert(name); };}let name ="John";// create a functionlet work =makeWorker();// call itwork(); // what will it show? "Pete" (name where created) or "John" (name where called)?
// 回答第 1 個問題,變數會使用最新的值,let name ="John";functionsayHi() {alert("Hi, "+ name);}name ="Pete"; // (*)sayHi(); // Pete
Nested functions
functionsayHiBye(firstName, lastName) {// helper nested function to use belowfunctiongetFullName() {return firstName +" "+ lastName; }alert( "Hello, "+getFullName() );alert( "Bye, "+getFullName() );}// 巢狀函式可以被返回作為新物件的屬性或直接作為結果。// 巢狀函式作為新物件屬性// constructor function returns a new objectfunctionUser(name) {// the object method is created as a nested functionthis.sayHi=function() {alert(name); };}let user =newUser("John");user.sayHi(); // the method "sayHi" code has access to the outer "name"// 巢狀函式作為結果functionmakeCounter() {let count =0;returnfunction() {return count++; // has access to the outer "count" };}let counter =makeCounter();alert( counter() ); // 0alert( counter() ); // 1alert( counter() ); // 2
for (let i =0; i <10; i++) {// Each loop has its own Lexical Environment// {i: value}}alert(i); // Error, no such variable
Code blocks
// 當 2 個腳本有相同痊癒變數會出現問題,用 {...} 可以解決這樣的問題。{// do some job with local variables that should not be seen outsidelet message ="Hello";alert(message); // Hello}alert(message); // Error: message is not defined
IIFE
// 在過去沒有 lexical environment,因此發明 immediately-invoked function expressions,// 函式有區域變數並立即執行,(function() {let message ="Hello";alert(message); // Hello})();// 沒有函式名稱// Try to declare and immediately call a functionfunction() { // <-- Error: Unexpected token (let message ="Hello";alert(message); // Hello}();// 不能宣告同時執行// syntax error because of parentheses belowfunctiongo() {}(); // <-- can't call Function Declaration immediately// Ways to create IIFE(function() {alert("Parentheses around the function");})();(function() {alert("Parentheses around the whole thing");}());!function() {alert("Bitwise NOT operator starts the expression");}();+function() {alert("Unary plus starts the expression");}();
Garbage collection
// 函式執行完,會被記憶體清除functionf() {let value1 =123;let value2 =456;}f();// 用閉包的特性,函式執行完仍在記憶體內,[[Environment] 指向函式。functionf() {let value =123;functiong() { alert(value); }return g;}let g =f(); // g is reachable, and keeps the outer lexical environment in memory// 函式被呼叫多次,相對應的 lexical environment,也會被儲存在記憶體。functionf() {let value =Math.random();returnfunction() { alert(value); };}// 3 functions in array, every one of them links to Lexical Environment (LE for short)// from the corresponding f() run// LE LE LElet arr = [f(),f(),f()];// 當全域變數被清除,函式消失functionf() {let value =123;functiong() { alert(value); }return g;}let g =f(); // while g is alive// there corresponding Lexical Environment livesg =null; // ...and now the memory is cleaned up
Real-life optimizations
// 實際狀況 JavaScript 引擎會進行優化,未作用的變數會被清除。// v8 在 debug 時無法使用區域變數functionf() {let value =Math.random();functiong() {debugger; // in console: type alert( value ); No such variable! }return g;}let g =f();g();// 會返回全域變數let value ="Surprise!";functionf() {let value ="the closest value";functiong() {debugger; // in console: type alert( value ); Surprise! }return g;}let g =f();g();