會有 hoisting 的特性。
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/var#var_hoisting
測試範例的輸出,是使用 chrome。
範例1:variable
第一個 console.log(x),輸出 undefined ,表示此時 x 不是全域變數了。
var x = 1; function bar() { console.log(x); // undefined var x = 2; console.log(x); // 2 } bar();因為 JavaScript 解譯器,猶如會默默的將變數名稱宣告,移置 scope 最上面。但變數值的定義,沒有移置最上面。
效果與下相同:
var x = 1; function bar() { var x; console.log(x); // undefined x = 2; console.log(x); // 2 } bar();
範例2:variable
console.log(x),都輸出 undefined ,表示 x 不是全域變數了。
var x = 1; function bar() { console.log(x); // undefined if(false){ var x = 2; } console.log(x); // undefined } bar();因為 JavaScript 解譯器,猶如會默默的將變數名稱宣告,移置 scope 最上面。但變數值的定義,沒有移置最上面。
就算原本區域變數宣告是在不會執行的區塊,亦不影響。
效果與下相同:
var x = 1; function bar() { var x; console.log(x); // undefined if(false){ x = 2; } console.log(x); // undefined } bar();
範例3:function declaration
以下程式碼,可以正常執行。foo() 輸出 123,表示 foo() 已經定義了。
function test() { foo(); // 會執行 function foo() { console.log("123"); // 123 }; } test();因為 JavaScript 解譯器,猶如會默默的將 function declaration,整個移到 scope 最上面。
效果與下相同:
function test() { function foo() { console.log("123"); // 123 }; foo(); // 會執行 } test();
範例4:function expression
以下程式碼,會發生錯誤,顯示 foo() 未定義,不是一個函式
function test() { foo(); // Uncaught TypeError: undefined is not a function var foo = function () { console.log("123"); }; } test();因為 JavaScript 解譯器,猶如會默默的將 function expression 的函數名稱,移到 scope 最上面。但 function body 沒有移至最上面。
效果與下相同:
function test() { var foo; foo(); // Uncaught TypeError: undefined is not a function foo = function () { console.log("123"); }; } test();
範例5:function declaration
以下程式碼,可以正常執行,表示 foo() 已經定義了。
function test() { foo(); // 會執行 if(false) { function foo() { console.log("123"); // 123 }; } } test();因為 JavaScript 解譯器,猶如會默默的將 function declaration,整個移到 scope 最上面。
就算原本 function declaration 是在不會執行的區塊,亦不影響
效果與下相同:
function test() { function foo() { console.log("123"); // 123 }; foo(); // 會執行 if(false) { } } test();
範例6:function declaration
在 bar() 裡面,使用 function declaration 方式,加一個跟全域變數 a 同名稱的 function a(),不管放在哪個位置,均會使 bar() 裡面的 a 變成區域變數。
var a = 1; function bar() { /* firebug 的 console.log 只會顯示 a(), 用 alert(a),才會顯示 function a() {var y = 123;} chrome、IE10 的 console.log 則都會顯示 function a() {var y = 123;} */ console.log(a); // function a() {var y = 123;} console.log(typeof a); // function a = 10; console.log(a); // 10 console.log(typeof a); // number return; function a() {var y = 123;} } bar(); console.log(a); // 1 console.log(typeof a); // number因為 JavaScript 解譯器,猶如會默默的將 function declaration,整個移到 scope 最上面。
因此在 function bar() 裡面的 a,變成區域變數。
效果與下相同:
var a = 1; function bar() { function a() {var y = 123;} console.log(a); // function a() {var y = 123;} console.log(typeof a); // function a = 10; console.log(a); // 10 console.log(typeof a); // number return; } bar(); console.log(a); // 1 console.log(typeof a); // number
範例7:function expression
註: http://stackoverflow.com/a/338053
這邊說 var baz = function spam() {console.log(123);}; 這種寫法
spam() 在 IE 還是可以執行,其他瀏覽器則是未定義
我測試在 IE10 測試 spam() 也是未定義,
但用開發者工具切換到 IE7、IE8、IE9,spam()則是有定義可以執行
baz(); //Uncaught TypeError: Property 'baz' of object [object Object] is not a function spam(); //Uncaught ReferenceError: spam is not defined var baz = function spam() {console.log(123);}; baz(); // 123 spam(); //Uncaught ReferenceError: spam is not defined效果與下相同:
var baz; baz(); //Uncaught TypeError: Property 'baz' of object [object Object] is not a function spam(); //Uncaught ReferenceError: spam is not defined baz = function spam() {console.log(123);}; baz(); // 123 spam(); //Uncaught ReferenceError: spam is not defined
範例8:function declaration
以下程式碼,foo() 會回傳 b
if(true){ function foo(){ return 'a'} }else{ function foo(){ return 'b'} } console.log(foo());// b因為 JavaScript 解譯器,猶如會默默的將 function declaration,整個移到 scope 最上面。
效果與下相同:
function foo(){ return 'a'} function foo(){ return 'b'} if(true){ }else{ } console.log(foo());// b
範例9:function expression
以下程式碼,foo() 會回傳 a
if(true){ var foo = function(){ return 'a'}; }else{ var foo = function(){ return 'b'}; } console.log(foo());// a因為 JavaScript 解譯器,猶如會默默的將 function expression 的函數名稱,移到 scope 最上面。但 function body 沒有移至最上面。
效果與下相同:
var foo; var foo; if(true){ foo = function(){ return 'a'}; }else{ foo = function(){ return 'b'}; } console.log(foo());// a
結論:
- 變數:
var x=1
效果如同 var x; 移至最上面,但 x=1 留在原處。 - function declaration:
function foo(){......}
效果如同 function foo(){ .....} 整個移至最上面。 - function expression:
var foo = function(){......};
效果如同 var foo;移至最上面,但 foo = function(){......}; 留在原處。 - 不管程式邏輯是否會執行到該程式碼,不會影響以上三點。
- function expression:
var foo = function abc(){......};
abc() 在 firefox、chrome、IE10 會無定義,IE7、IE8、IE9 有定義。
其他:
以下,跟 C 語言不同,if 裡面再宣告一次同名稱的變數,該變數 scope 跟外面是相通的。
var x = 1; console.log(x); // 1 if (true) { var x = 2; console.log(x); // 2 } console.log(x); // 2如果想在 if {...} 裡面,生成一個暫時的 x 區域變數,可用以下方法。
var x = 1; console.log(x); // 1 if (true) { (function () { var x = 2; console.log(x); // 2 }()); } console.log(x); // 1參考:
http://www.adequatelygood.com/JavaScript-Scoping-and-Hoisting.html
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions_and_function_scope#Function_constructor_vs._function_declaration_vs._function_expression
http://docstore.mik.ua/orelly/webprog/jscript/ch04_03.htm
http://www.ptt.cc/bbs/Web_Design/M.1371040928.A.C95.html
http://javascriptweblog.wordpress.com/2010/07/06/function-declarations-vs-function-expressions/
沒有留言:
張貼留言