《JavaScript高級(jí)程序設(shè)計(jì)》Chapter 7 函數(shù)表達(dá)式

Chapter 7 函數(shù)表達(dá)式

基本概念

  1. 函數(shù)聲明提升:執(zhí)行代碼前會(huì)先讀取函數(shù)聲明臂外。

    • 函數(shù)聲明
    function sayHi() {
        alert("Hi!");
    }
    
    • 函數(shù)表達(dá)式
    var sayHi = function() {
        alert("Hi!");
    }
    
  2. 匿名函數(shù):function關(guān)鍵字后沒有標(biāo)識(shí)符配猫。

  3. 不要在條件語句中聲明函數(shù),因?yàn)闂l件語句可能會(huì)被忽略拼苍。但是可以使用函數(shù)表達(dá)式独令。

遞歸

  1. 函數(shù)名遞歸(略)
  2. 使用arguments.callee指針實(shí)現(xiàn)遞歸
function factorial(num) {
    if (num < 1) {
        return 1;
    } else {
        return num * arguments.callee(num - 1);
    }
}
  1. 在嚴(yán)格模式下愕秫,不能通過腳本訪問arguments.callee,可以通過如下方法
var factorial = (function f(num) {
    if (num <= 1) {
        return 1;
    } else {
        return num * f(num - 1);
    }
});

閉包

  1. 定義:閉包是指有權(quán)訪問另一個(gè)函數(shù)作用域中的變量的函數(shù)挟炬。
  2. 創(chuàng)建閉包的常見方式鸥滨,是在一個(gè)函數(shù)內(nèi)部創(chuàng)建另一個(gè)函數(shù)
function createComparisonFunction(propertyName) {
    return function(object1, object2) {
        var value1 = object1[propertyName];
        var value2 = object2[propertyName];
        if (value1 < value2) return -1;
        else if (value1 < value2) return 1;
        else return 0;
    }
}
  1. 作用域鏈:當(dāng)某個(gè)函數(shù)被調(diào)用時(shí),會(huì)創(chuàng)建一個(gè)執(zhí)行環(huán)境及相應(yīng)的作用域鏈谤祖。然后婿滓,使用arguments和其他命名參數(shù)的值來初始化函數(shù)的活動(dòng)對象。但在作用域鏈中粥喜,使用arguments和其他命名參數(shù)的值來初始化函數(shù)的活動(dòng)對象凸主。但是在作用域鏈中,外部函數(shù)的活動(dòng)對象始終處于第二位额湘,外部函數(shù)的外部函數(shù)的活動(dòng)對象處于第三位.....直到作為作用域終點(diǎn)的全局執(zhí)行環(huán)境卿吐。

  2. 作用域鏈的本質(zhì)是一個(gè)指向變量對象的指針列表旁舰,它只引用但不實(shí)際包含對象。

  3. 本地活動(dòng)對象 & 全局變量對象

    • 在另一個(gè)函數(shù)內(nèi)部定義的函數(shù)會(huì)將包含函數(shù)的活動(dòng)對象添加到它的作用域鏈中嗡官。包含函數(shù)執(zhí)行完畢后箭窜,其活動(dòng)對象不會(huì)被銷毀,因?yàn)楸话哪涿瘮?shù)的作用域鏈仍然在引用這個(gè)活動(dòng)對象衍腥。直到匿名函數(shù)被銷毀后磺樱,該函數(shù)的活動(dòng)對象才會(huì)被銷毀。(仔細(xì)看書)
  4. 由于閉包會(huì)攜帶包含它的函數(shù)作用域婆咸,因此會(huì)比其他函數(shù)占用更多的內(nèi)存竹捉。

  5. 閉包與變量

    • 閉包只能取得包含函數(shù)中任何變量的最后一個(gè)值
    function createFunctions() {
        var result = new Array();
        for(var i = 0; i < 10; i++) {
            result[i] = function() {
                return i;
            }
        }
        return result;
    }
    
    • createFunctions()函數(shù)會(huì)返回一個(gè)函數(shù)數(shù)組,并且每個(gè)函數(shù)都返回10尚骄。因?yàn)槊總€(gè)函數(shù)的作用域鏈中都保存著createFunctions()函數(shù)的活動(dòng)對象活孩,所以它們引用的都是同一個(gè)變量i。當(dāng)createFunctions()函數(shù)返回后乖仇,變量i的值是10憾儒,此時(shí)每個(gè)函數(shù)都引用著保存變量i的同一個(gè)變量對象,所以在每個(gè)函數(shù)內(nèi)部i的值都是10乃沙。解決方法如下
    function createFunctions() {
        var result = new Array();
        for(var i = 0; i < 10; i++) {
            result[i] = function(num) {
                return function() {
                    return num;
                };
                
            }(i);
        }
        return result;
    }
    
  6. 關(guān)于this對象

    • 匿名函數(shù)的執(zhí)行環(huán)境具有全局性起趾,因此其this通常指向window。
    var name = 'Lawrence';
    var object = {
        name: 'Qwerty',
        getName: function() {
            return function() {
                return this.name;
            }
        }
    };
    alert(object.getName()); // 'Lawrence'
    
    • 匿名函數(shù)沒有取得其包含作用域的this對象:每個(gè)函數(shù)在被調(diào)用的時(shí)候都會(huì)自動(dòng)取得兩個(gè)特殊變量警儒,this和arguments训裆。內(nèi)部函數(shù)在搜索這兩個(gè)變量時(shí),只會(huì)搜索到其活動(dòng)對象為止蜀铲,因此永遠(yuǎn)不可能直接訪問外部函數(shù)中的這兩個(gè)變量边琉。解決方法:把外部作用域中的this對象保存在一個(gè)閉包能夠訪問到的變量里。
    var name = 'Lawrence';
    var object = {
        name: 'Qwerty',
        getName: function() {
            var that = this;
            return function() {
                return that.name;
            }
        }
    };
    alert(object.getName()); // 'Qwerty'
    
    • arguments也存在同樣的問題
  7. 內(nèi)存泄漏

    • IE9-的版本中记劝,如果閉包的作用域鏈中保存著一個(gè)HTML元素变姨,那么就意味著該元素將無法被銷毀。(具體見書)

模仿塊級(jí)作用域

  1. Java沒有塊級(jí)作用域厌丑。在塊語句中定義的變量定欧,實(shí)際上是在包含函數(shù)中而非語句中創(chuàng)建的。
  2. 可以通過匿名函數(shù)模仿塊級(jí)作用域
(function() {
    // 這里是塊級(jí)作用域
})(); // 包裹function的括號(hào)是必需的怒竿。
  1. 這種做法可以減少閉包占用內(nèi)存的問題砍鸠,因?yàn)闆]有指向匿名函數(shù)的引用。

私有變量

  1. JavaScript沒有私有成員的概念耕驰,所有對象的屬性都是公有的爷辱。但是有私有變量的概念。任何在函數(shù)中定義的變量,都可以認(rèn)為是私有變量饭弓。私有變量包括函數(shù)參數(shù)巩检、局部變量和在函數(shù)內(nèi)部定義的其他函數(shù)。示启、

  2. 有權(quán)訪問私有變量和私有函數(shù)的公有方法稱為特權(quán)方法兢哭。有兩種在對象上創(chuàng)建特權(quán)方法的方式

    • 在構(gòu)造函數(shù)中定義特權(quán)方法
    function MyObject() {
        var privateVariable = 10;
        function privateFunction() {
            return false;
        }
        // 特權(quán)方法
        this.publicMethod = function() {
            privateVariable++;
            return privateFunction();
        };
    }
    
  3. 利用私有和特權(quán)成員,可以隱藏那些不應(yīng)該被直接修改的數(shù)據(jù)夫嗓。

  4. 靜態(tài)私有變量

    • 通過在私有作用域中定義私有變量或函數(shù)迟螺,同樣可以創(chuàng)建特權(quán)方法,其基本模式如下

(function() {
var privateVariable = 10;
function privateFunction() {
return false;
}
MyObject = function() {
}; // 全局變量
// 特權(quán)方法
MyObject.prototype.publicMethod = function() {
privateVariable++;
return privateFunction();
};
})();
```

* 多查找作用域鏈中的一個(gè)層次舍咖,就會(huì)在一定程度上影響查找速度矩父。
  1. 模塊模式

    • 為單例創(chuàng)建私有變量和特權(quán)方法。JavaScript以對象字面量創(chuàng)建單例對象排霉。模塊模式通過為單例添加私有變量和特權(quán)方法使其得到增強(qiáng)
    var singleton = function() {
        var privateVariable = 10;
        function privateFunction() {
            return false;
        }
        //特權(quán)方法和屬性
        return {
            publicProperty: true;
            publicMethod: function() {
                privateVariable++;
                return privateFunction();
            }
        };
    }();
    
* 這種模式在需要對單例進(jìn)行某些初始化窍株,同時(shí)又需要維護(hù)其私有變量時(shí)是非常有用的。

```
var application = function() {
    var components = new Array();
    components.push(new BaseComponent());
    return {
        getComponentCount: function() {
            return components.length;
        },
        registerComponent: function(component) {
            if(typeof component == 'object') {
                components.push(component);
            }
        }
    };
}();
```
  1. 增強(qiáng)的模塊模式

    • 在返回對象之前加入對其增強(qiáng)的代碼攻柠。
    var singleton = function() {
        var privateVariable = 10;
        function privateFunction() {
            return false;
        }
        var object = new CustomType();
        object.publicProperty = true;
        object.publicMethod = function() {
            privateVariable++;
            return privateFunction();
        };
        return object;
    }();
    
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末球订,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子瑰钮,更是在濱河造成了極大的恐慌冒滩,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,946評(píng)論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件浪谴,死亡現(xiàn)場離奇詭異开睡,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)苟耻,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,336評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門篇恒,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人凶杖,你說我怎么就攤上這事胁艰。” “怎么了官卡?”我有些...
    開封第一講書人閱讀 169,716評(píng)論 0 364
  • 文/不壞的土叔 我叫張陵蝗茁,是天一觀的道長醋虏。 經(jīng)常有香客問我寻咒,道長,這世上最難降的妖魔是什么颈嚼? 我笑而不...
    開封第一講書人閱讀 60,222評(píng)論 1 300
  • 正文 為了忘掉前任毛秘,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘叫挟。我一直安慰自己艰匙,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,223評(píng)論 6 398
  • 文/花漫 我一把揭開白布抹恳。 她就那樣靜靜地躺著员凝,像睡著了一般。 火紅的嫁衣襯著肌膚如雪奋献。 梳的紋絲不亂的頭發(fā)上健霹,一...
    開封第一講書人閱讀 52,807評(píng)論 1 314
  • 那天,我揣著相機(jī)與錄音瓶蚂,去河邊找鬼糖埋。 笑死,一個(gè)胖子當(dāng)著我的面吹牛窃这,可吹牛的內(nèi)容都是我干的瞳别。 我是一名探鬼主播,決...
    沈念sama閱讀 41,235評(píng)論 3 424
  • 文/蒼蘭香墨 我猛地睜開眼杭攻,長吁一口氣:“原來是場噩夢啊……” “哼祟敛!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起兆解,我...
    開封第一講書人閱讀 40,189評(píng)論 0 277
  • 序言:老撾萬榮一對情侶失蹤垒棋,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后痪宰,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體叼架,經(jīng)...
    沈念sama閱讀 46,712評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,775評(píng)論 3 343
  • 正文 我和宋清朗相戀三年衣撬,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了乖订。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,926評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡具练,死狀恐怖乍构,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情扛点,我是刑警寧澤哥遮,帶...
    沈念sama閱讀 36,580評(píng)論 5 351
  • 正文 年R本政府宣布,位于F島的核電站陵究,受9級(jí)特大地震影響眠饮,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜铜邮,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,259評(píng)論 3 336
  • 文/蒙蒙 一仪召、第九天 我趴在偏房一處隱蔽的房頂上張望寨蹋。 院中可真熱鬧,春花似錦扔茅、人聲如沸已旧。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,750評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽运褪。三九已至,卻和暖如春玖瘸,著一層夾襖步出監(jiān)牢的瞬間吐句,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,867評(píng)論 1 274
  • 我被黑心中介騙來泰國打工店读, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留嗦枢,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,368評(píng)論 3 379
  • 正文 我出身青樓屯断,卻偏偏與公主長得像文虏,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子殖演,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,930評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容