let
宣告的變數不會有 hoisting 變數提升的特性只有類似的概念,var
宣告的變數才會,下方會有範例。
let
一樣有創造階段和執行階段,類似 Hoisting 提升的概念,只是它在提升時不會賦予變數 undefined
的值,而是出現「 暫時性死區 TDZ 」,這個暫時性死區無法存取這個變數而出現錯誤訊息 Uncaught ReferenceError: Cannot access 'Ming' before initialization
。
// -----透過函式宣告
// 會回傳 5
console.log(isTotal(5));
function isTotal(num) {
return num + num;
}
// -----函式運算子 Function expression
// 會顯示錯誤訊息 Uncaught ReferenceError
console.log(isCount(5));
var isCount= function (num) {
return num + num;
}
➊ 函式陳述式 Function statement :
在創造階段,會把記憶體空間與整個函式的內容都準備好並載入進來。所以函式在創造階段就已經可以運行。範例
callName();
function callName() {
console.log('呼叫小明');
}
// ============= 印出 呼叫小明
➋ 變數 :
❗注意 : 這邊 let
宣告的變數不會有變數提升的特性,有變數提升特性的只有 var
宣告的變數。( 詳細解說請看 「 Kuro - 008 天重新認識 JavaScript 」 2-38 ~ 2-40 頁 )
console.log(Ming);
var Ming; // 創造階段
Ming = '小明'; // 執行階段
// ============= undefined
console.log(Ming);
let Ming;
Ming = '小明';
// ============= let宣告變數沒有提升特性,所以顯示錯誤訊息 ReferenceError
// 函式表達式( Funciton expression )
var callName = function () {
console.log('呼叫小明');
}
// =========== 拆解
// 創造階段
var callName;
// 執行階段
callName = function () {
console.log('呼叫小明');
}
callName();
創造環境階段,會把程式碼裡面所有變數挑出來,在記憶體上面分別給它們空間,一直到執行階段才會把這些程式碼依序執行,並且賦予它值。
範例 1
key
右方是值
。在 hoisting 創造環境這階段時,記憶體會先放入 key 。undefined
,直到執行時才會把值套用上來。/
var Ming = '小明';
console.log(Ming);
// ========== 拆解
var Ming; // 創造階段
Ming = '小明'; // 執行階段
console.log(Ming);
上方程式碼執行時會分為兩個步驟 :
var Ming;
。Ming
。範例 2
創造階段
undefined
。callName();
function callName() {
console.log('呼叫小明');
}
拆解:
callName();
移到最上方是不會出錯的。function callName()
會被移至上方。// 創造階段
function callName() {
console.log('呼叫小明');
}
// 執行
callName();
答案: 會印出 呼叫小明
// 可正確呼叫
var callName = function () {
console.log('呼叫小明');
}
callName();
// undefined
callName();
var callName = function () {
console.log('呼叫小明');
}
解說 :
函式表達式創造階段與變數一樣會先提出變數給予記憶體空間。
在執行階段,才把 function 賦予到變數 callName 上。要運行這段函式必須在函式賦予到值上才能運行此段函式。
// 創造階段
var callName;
// 執行階段
callName = function () {
console.log('呼叫小明');
}
callName();
// 題目
function callName() {
console.log('呼叫小明 1');
}
var callName = function () {
console.log('呼叫小明 2');
}
callName();
解說 :
在創造階段函式優先,所以函式先被提至最上面 → 才換變數往前移 → 並賦予值的動作。
// 創造階段
function callName() {
console.log('呼叫小明 1');
}
var callName;
// 執行階段
callName = function () {
console.log('呼叫小明 2');
}
callName();
在執行階段,變數 callName
重新被另一個函式 function() { console.log('呼叫小明 2');}
給覆蓋掉,所以在執行 callName();
會出現 呼叫小明 2
。
var callName = function(){}
在前或是函式陳述式 function callName()
在前,都會印出 呼叫小明 2
。答案:呼叫小明 2
// 題目
function callName() {
console.log('呼叫小明 1');
}
callName();
var callName = function () {
console.log('呼叫小明 2');
}
拆解 :
提升順序 : 函式 → 變數 → 賦予值。
// 創造階段
function callName() {
console.log('呼叫小明 1');
}
var callName;
// 執行階段
callName();
callName = function () {
console.log('呼叫小明 2');
}
創造階段先宣告函式,定義變數 callName 為空值。執行 callName();
這個函式取得 console.log('呼叫小明 1');
。
答案:呼叫小明 1'
callName();
function callName() {
console.log(Ming);
}
var Ming = '小明';
答案
答案為 undefined
。
先把創造階段與執行階段分開。提出函式 → 提出變數 → 賦予值。
// 創造
function callName() {
console.log(Ming);
}
var Ming;
// 執行
callName();
Ming = '小明';
創造階段就先宣告函式,定義這個變數為空值。呼叫 callName();
這個函式目前所取的值是全域的 Ming
,目前這個變數 Ming
還未被賦予值,答案就為 undefined
。