標籤:font define else typeof 概念 listener new color 標識
繼續湯姆大叔的js之旅。
揭秘命名函數運算式
函數運算式和函式宣告
湯姆大叔在部落格中引用ECMA規範:函式宣告必須帶有標識符,函數運算式可以省略。對於我來說這些概念的東西真是不所適從。還是大叔的執行個體帶勁。上執行個體如下:
function foo(){};//鬼都知道是聲明
var bar = function foo(){};//鬼也知道是運算式
new function bar(){};
(function() {
function bar(){};//這也是聲明
})();這些大家看看應該都很好理解。在這裡大叔還總結了一點可以在大部分情況下快速的判斷是運算式還是函式宣告"賦值一定是運算式,不帶函數名一定是運算式"。
還有一種函數運算式是不太常見,就是用括弧括住的(function foo(){})。這個是運算式的原因很簡單括弧()是一個分組操作符,而更重要的是分組操作符的內部只能包含運算式。
函數語句
雖然提到這個,但是現在可能還是存在不支援(chrome瀏覽器我看是支援的)(這點兒我自己沒有細想也沒有完全的去理解)。
命名函數運算式
直接上執行個體var bar = function foo(){};這是有效命名函數運算式,大叔特意強調新定義函數範圍內有效。看大叔的這個例子吧,看懂就理解了:
function foo(){return bar();}
var bar = (function(){
if(window.addEventListener){
return function bar(){
return baz();
};
}
else if(window.attachEvent){
return function bar(){
return baz();
};
}
})();
function baz(){
debugger;
}
foo();
我們來看看這些函數調用過程:foo->bar;而bar是一個命名函數運算式,由內部的兩次返回之後是baz,也就是說baz被bar調用。bar->baz;baz內部調用debugger。
js的bug
- 函數運算式的標識符泄露到外部的範圍;執行個體1
- 將命名函數運算式同時作為函式宣告和函數運算式;執行個體2
- 命名函數運算式建立兩個截然不同的函數對象;執行個體3
- 僅僅順序解析函式宣告而忽略條件陳述式塊;執行個體4
執行個體1:var f = function g(){};typeof g;//“function”;親自在IE8上測試成功。這是不應該的,標識符g被解析成函數,可能前端程式員在寫程式的好多時候的bug就是這樣引起的。
執行個體2:var typeof g;var f = function g();同樣在ie8下是function,在chrome下是undefined
執行個體3:var f = function g(){};f === g;f.expando = ‘foo‘;g.expendo;測試chrome下不能運行(顯示g沒有定義)。
執行個體4:var f = function g(){return 1;};if(false){f=function g(){return 2;};} g();測試chrome下是g沒有定義。
這麼多問題,其實都是把標識符作為一個函式宣告了(個人理解)。
js記憶體管理
先看大叔給的執行個體,然後我們來理解大叔給我們帶來的js記憶體管理這些內容。var f = (function(){if(true){return function g(){};}return function g(){};})();。在匿名函數調用返回的函數(就是帶有標識符g的函數) ,然後賦值給外部的f;這個對象與返回的函數對象不是一個事情,多餘的g函數就死在返回函數的閉包中。這就是記憶體問題的產生原因。
(個人對這裡的一個備忘,當匿名函數返回的函數是怎麼賦值給f,這個賦值的底層是怎麼一個實現)
解決辦法如下執行個體所示,就是人為手動斷開引用。
var f = (function(){var f,g;if(true){f=function g(){};}else{f=function g(){};} g=null; return f;})();
我讀湯姆大叔的深入理解js(二)