鍍金池/ 教程/ HTML/ Function 模式(下篇)
代碼復(fù)用模式(避免篇)
S.O.L.I.D 五大原則之接口隔離原則 ISP
設(shè)計(jì)模式之狀態(tài)模式
JavaScript 核心(晉級(jí)高手必讀篇)
設(shè)計(jì)模式之建造者模式
JavaScript 與 DOM(上)——也適用于新手
設(shè)計(jì)模式之中介者模式
設(shè)計(jì)模式之裝飾者模式
設(shè)計(jì)模式之模板方法
設(shè)計(jì)模式之外觀模式
強(qiáng)大的原型和原型鏈
設(shè)計(jì)模式之構(gòu)造函數(shù)模式
揭秘命名函數(shù)表達(dá)式
深入理解J avaScript 系列(結(jié)局篇)
執(zhí)行上下文(Execution Contexts)
函數(shù)(Functions)
《你真懂 JavaScript 嗎?》答案詳解
設(shè)計(jì)模式之適配器模式
設(shè)計(jì)模式之組合模式
設(shè)計(jì)模式之命令模式
S.O.L.I.D 五大原則之單一職責(zé) SRP
編寫(xiě)高質(zhì)量 JavaScript 代碼的基本要點(diǎn)
求值策略
閉包(Closures)
對(duì)象創(chuàng)建模式(上篇)
This? Yes,this!
設(shè)計(jì)模式之代理模式
變量對(duì)象(Variable Object)
S.O.L.I.D 五大原則之里氏替換原則 LSP
面向?qū)ο缶幊讨话憷碚?/span>
設(shè)計(jì)模式之單例模式
Function 模式(上篇)
S.O.L.I.D 五大原則之依賴倒置原則 DIP
設(shè)計(jì)模式之迭代器模式
立即調(diào)用的函數(shù)表達(dá)式
設(shè)計(jì)模式之享元模式
設(shè)計(jì)模式之原型模式
根本沒(méi)有“JSON 對(duì)象”這回事!
JavaScript 與 DOM(下)
面向?qū)ο缶幊讨?ECMAScript 實(shí)現(xiàn)
全面解析 Module 模式
對(duì)象創(chuàng)建模式(下篇)
設(shè)計(jì)模式之職責(zé)鏈模式
S.O.L.I.D 五大原則之開(kāi)閉原則 OCP
設(shè)計(jì)模式之橋接模式
設(shè)計(jì)模式之策略模式
設(shè)計(jì)模式之觀察者模式
代碼復(fù)用模式(推薦篇)
作用域鏈(Scope Chain)
Function 模式(下篇)
設(shè)計(jì)模式之工廠模式

Function 模式(下篇)

介紹

本篇我們介紹的一些模式稱為初始化模式和性能模式,主要是用在初始化以及提高性能方面,一些模式之前已經(jīng)提到過(guò),這里只是做一下總結(jié)。

立即執(zhí)行的函數(shù)

在本系列第 4 篇的《立即調(diào)用的函數(shù)表達(dá)式》中,我們已經(jīng)對(duì)類(lèi)似的函數(shù)進(jìn)行過(guò)詳細(xì)的描述,這里我們只是再舉兩個(gè)簡(jiǎn)單的例子做一下總結(jié)。

// 聲明完函數(shù)以后,立即執(zhí)行該函數(shù)
(function () {
    console.log('watch out!');
} ());  
//這種方式聲明的函數(shù),也可以立即執(zhí)行
!function () {
    console.log('watch out!');
} ();  
// 如下方式也都可以哦
~function () { /* code */ } ();
-function () { /* code */ } ();
+function () { /* code */ } ();

立即執(zhí)行的對(duì)象初始化

該模式的意思是指在聲明一個(gè)對(duì)象(而非函數(shù))的時(shí)候,立即執(zhí)行對(duì)象里的某一個(gè)方法來(lái)進(jìn)行初始化工作,通常該模式可以用在一次性執(zhí)行的代碼上。

({
    // 這里你可以定義常量,設(shè)置其它值
    maxwidth: 600,
    maxheight: 400,  
    //  當(dāng)然也可以定義utility方法
    gimmeMax: function () {
        return this.maxwidth + "x" + this.maxheight;
    },  
    // 初始化
    init: function () {
        console.log(this.gimmeMax());
        // 更多代碼...
    }
}).init();  // 這樣就開(kāi)始初始化咯

分支初始化

分支初始化是指在初始化的時(shí)候,根據(jù)不同的條件(場(chǎng)景)初始化不同的代碼,也就是所謂的條件語(yǔ)句賦值。之前我們?cè)谧鍪录幚淼臅r(shí)候,通常使用類(lèi)似下面的代碼:

var utils = {
    addListener: function (el, type, fn) {
        if (typeof window.addEventListener === 'function') {
            el.addEventListener(type, fn, false);
        } else if (typeof document.attachEvent !== 'undefined') {
            el.attachEvent('on' + type, fn);
        } else {
            el['on' + type] = fn;
        }
    },
    removeListener: function (el, type, fn) {
    }
};

我們來(lái)改進(jìn)一下,首先我們要定義兩個(gè)接口,一個(gè)用來(lái)add事件句柄,一個(gè)用來(lái) remove 事件句柄,代碼如下:

var utils = {
    addListener: null,
    removeListener: null
};

實(shí)現(xiàn)代碼如下:

if (typeof window.addEventListener === 'function') {
    utils.addListener = function (el, type, fn) {
        el.addEventListener(type, fn, false);
    };
} else if (typeof document.attachEvent !== 'undefined') { // IE
    utils.addListener = function (el, type, fn) {
        el.attachEvent('on' + type, fn);
    };
    utils.removeListener = function (el, type, fn) {
        el.detachEvent('on' + type, fn);
    };
} else { // 其它舊瀏覽器
    utils.addListener = function (el, type, fn) {
        el['on' + type] = fn;
    };
    utils.removeListener = function (el, type, fn) {
        el['on' + type] = null;
    };
}

用起來(lái),是不是就很方便了?代碼也優(yōu)雅多了。

自聲明函數(shù)

一般是在函數(shù)內(nèi)部,重寫(xiě)同名函數(shù)代碼,比如:

var scareMe = function () {
    alert("Boo!");
    scareMe = function () {
        alert("Double boo!");
    };
};

這種代碼,非常容易使人迷惑,我們先來(lái)看看例子的執(zhí)行結(jié)果:

// 1. 添加新屬性
scareMe.property = "properly";
// 2. scareMe賦與一個(gè)新值
var prank = scareMe;
// 3. 作為一個(gè)方法調(diào)用
var spooky = {
    boo: scareMe
};
// 使用新變量名稱進(jìn)行調(diào)用
prank(); // "Boo!"
prank(); // "Boo!"
console.log(prank.property); // "properly"
// 使用方法進(jìn)行調(diào)用
spooky.boo(); // "Boo!"
spooky.boo(); // "Boo!"
console.log(spooky.boo.property); // "properly"

通過(guò)執(zhí)行結(jié)果,可以發(fā)現(xiàn),將定于的函數(shù)賦值與新變量(或內(nèi)部方法),代碼并不執(zhí)行重載的 scareMe 代碼,而如下例子則正好相反:

// 使用自聲明函數(shù)
scareMe(); // Double boo!
scareMe(); // Double boo!
console.log(scareMe.property); // undefined

大家使用這種模式時(shí),一定要非常小心才行,否則實(shí)際結(jié)果很可能和你期望的結(jié)果不一樣,當(dāng)然你也可以利用這個(gè)特殊做一些特殊的操作。

內(nèi)存優(yōu)化

該模式主要是利用函數(shù)的屬性特性來(lái)避免大量的重復(fù)計(jì)算。通常代碼形式如下:

var myFunc = function (param) {
    if (!myFunc.cache[param]) {
        var result = {};
        // ... 復(fù)雜操作 ...
        myFunc.cache[param] = result;
    }
    return myFunc.cache[param];
};
// cache 存儲(chǔ)
myFunc.cache = {};

但是上述代碼有個(gè)問(wèn)題,如果傳入的參數(shù)是 toString 或者其它類(lèi)似 Object 擁有的一些公用方法的話,就會(huì)出現(xiàn)問(wèn)題,這時(shí)候就需要使用傳說(shuō)中的 hasOwnProperty 方法了,代碼如下:

var myFunc = function (param) {
    if (!myFunc.cache.hasOwnProperty(param)) {
        var result = {};
        // ... 復(fù)雜操作 ...
        myFunc.cache[param] = result;
    }
    return myFunc.cache[param];
};  
// cache 存儲(chǔ)
myFunc.cache = {};

或者如果你傳入的參數(shù)是多個(gè)的話,可以將這些參數(shù)通過(guò) JSON 的 stringify 方法生產(chǎn)一個(gè) cachekey 值進(jìn)行存儲(chǔ),代碼如下:

var myFunc = function () {
    var cachekey = JSON.stringify(Array.prototype.slice.call(arguments)),
        result;
    if (!myFunc.cache[cachekey]) {
        result = {};
        // ... 復(fù)雜操作 ...
        myFunc.cache[cachekey] = result;
    }
    return myFunc.cache[cachekey];
};  
// cache 存儲(chǔ)
myFunc.cache = {};

或者多個(gè)參數(shù)的話,也可以利用 arguments.callee 特性:

var myFunc = function (param) {
    var f = arguments.callee,
        result;
    if (!f.cache[param]) {
        result = {};
        // ... 復(fù)雜操作 ...
        f.cache[param] = result;
    }
    return f.cache[param];
};  
// cache 存儲(chǔ)
myFunc.cache = {};

總結(jié)

就不用總結(jié)了吧,大家仔細(xì)看代碼就行咯