【讀書筆記】讀《JavaScript模式》 - JavaScript函數經常使用模式

  API模式:回調模式、配置對象、返回函數;node

  初始化模式:即時函數、即時對象初始化、初始化分支;瀏覽器

  性能模式:備忘模式、自定義模式緩存

 1 //*********************** API模式 ***********************
 2 /**
 3  * ---------------------- 回調模式 ----------------------
 4  * 
 5  * 1>要寫出通用和可複用的代碼,回調模式能夠幫助實現這種通用化。
 6  * 2>不須要預測和實現能想到的每一項功能,由於這樣會迅速使咱們的代碼膨脹,
 7  *     而絕大多數用戶永遠不會須要其中大量的功能。相反,能夠專一於核心功能並提供「掛鉤」形式的回調函數,
 8  *     這會使咱們很容易構建、擴展,以及自定義咱們的方法。
 9  */
10 //方式一
11 var findNodes = function () {
12     var i = 10000,
13         nodes = [],
14         found;
15     while (i) {
16         i -= 1;
17         //這裏是複雜的業務邏輯
18         nodes.push(found);
19     }
20     return nodes;
21 }
22 
23 var hide = function (nodes) {
24     for (var i = 0, len = nodes.length; i < len; i += 1) {
25         nodes[i].style.display = 'none';
26     }
27 }
28 
29 hide(findNodes());
30 
31 //方式二
32 var findNodes = function (callback) {
33     var i = 10000,
34         nodes = [],
35         found;
36     while (i) {
37         i -= 1;
38         //這裏是複雜的業務邏輯
39         if (typeof callback === 'function') {
40             callback(found);
41         }
42         nodes.push(found);
43     }
44     return nodes;
45 }
46 
47 var hide = function (node) {
48     node.style.display = 'none';
49 }
50 
51 findNodes(hide);
52 
53 //簡潔點,將回調函數直接寫在findNodes函數中
54 findNodes(function (node) {
55     node.style.display = 'block';
56 })
57 
58 /**
59  * ---------------------- 配置對象模式 ----------------------
60  * 
61  * 封裝傳遞參數爲一個對象,靈活了函數的調用方式,何樂而不爲
62  */
63 function addPerson(name, gender, age, address) {
64     //...
65 }
66 
67 //將參數封裝
68 var conf = {
69     name: 'king',
70     gender: 'male',
71     age: 25,
72     address: 'xxxxxx'
73 }
74 addPerson(conf);
75 
76 //簡寫之
77 addPerson({
78     name: 'king',
79     gender: 'male',
80     age: 25,
81     address: 'xxxxxx'
82 })
83 
84 /**
85  * ---------------------- 返回函數模式 ----------------------
86  * 
87  * 函數裏面返回函數,它建立了一個閉包,可使用這個閉包存儲一些私有數據,
88  * 而這些數據僅可被該返回函數訪問,但外部代碼卻沒法訪問。
89  */
90 var setup = function () {
91     var count = 0;
92     return function () {
93         return count++;
94     }
95 }
96 var next = setup();
97 next();    //1
98 next();    //2
99 next();    //3
//*********************** 初始化模式 ***********************
/**
 * ---------------------- 即時函數模式 ----------------------
 */
//文件module1.js中定義的模塊module1
(function () {
    //模塊1的全部代碼
})();

//文件module2.js中定義的模塊module2
(function () {
    //模塊2的全部代碼
})();

/**
 * ---------------------- 即時對象初始化模式 ----------------------
 * 
 * 這種模式的優勢與即時函數模式的優勢是相同的:能夠在執行一次性的初始化任務時保護全局命名空間。、
 * 與僅僅將一堆代碼包裝到匿名函數的方法相比。這種模式看起來設計更多的語法特徵,
 * 可是若是初始化任何更加複雜(它們也每每的確比較複雜),它會使整個初始化過程顯得更有結構化。
 * 其語法結構以下:
 * ({...}).init();
 * ({...}.init());
 */
({
    name: 'king',
    password: '123',
    say: function () {
        return 'I am ' + this.name + ', and my password is ' + this.password;
    },
    init: function () {
        console.log(this.say());
    }
    /**
     * 這種模式主要適用於一次性的任務,並且在init()完畢後也沒有保存對該對象的訪問。
     * 若是想在init()完畢後保存對該對象的一個引用,能夠經過在init()尾部添加"return this;"語句實現該功能。
     */
}).init();    //I am king, and my password is 123

/**
 * ---------------------- 初始化時分支模式 ----------------------
 */
//每次調用utils.addListener()或utils.removeListener()時,都會重複地進行相同檢查
var utils = {
    addListener: function (elem, type, fn) {
        if (typeof window.addEventListener === 'function') {
            elem.addEventListener(type, fn, false);
        } else if (typeof window.attachEvent === 'function') {    //IE
            elem.attachEvent('on' + type, fn);
        } else {
            elem['on' + type] = fn;
        }
    },
    removeListener: function () {
        if (typeof window.removeEventListener === 'function') {
            elem.removeEventListener(type, fn, false);
        } else if (typeof window.detachEvent === 'function') {    //IE
            elem.detachEvent('on' + type, fn);
        } else {
            elem['on' + type] = null;
        }
    }
}

//採用分支
var utils = {
    addListener: null,
    removeListener: null
}
//分開嗅探瀏覽器特徵,而後使用加載時分支僅執行一次嗅探
if (typeof window.addEventListener === 'function') {
    utils.addListener = function (elem, type, fn) {
        elem.addEventListener(type, fn, false);
    };
    utils.removeListener = function (elem, type, fn) {
        elem.removeListener(type, fn, false);
    };
} else if (typeof window.detachEvent === 'function') {    //IE
    utils.addListener = function (elem, type, fn) {
        elem.attachEvent('on' + type, fn);
    };
    utils.removeListener = function (elem, type, fn) {
        elem.detachEvent('on' + type, fn);
    };
} else {
    utils.addListener = function (elem, type, fn) {
        elem['on' + type] = fn;
    };
    utils.removeListener = function (elem, type, fn) {
        elem['on' + type] = null;
    };
}
//*********************** 性能模式 ***********************
/**
 * ---------------------- 備忘模式 ----------------------
 * 
 * 使用函數屬性以便使得計算過的值無須再次計算
 */
var myfunc = function (param) {
    if (!myfunc.cache[param]) {
        var result = {};
        //...開銷很大的操做...
        myfunc.cache[param] = result;
    }
    return myfunc.cache[param];
}
//緩存存儲
myfunc.cache = {};


/**
 * ---------------------- 自定義函數模式 ----------------------
 * 
 * 當函數有一些初始化準備工做要作,而且僅須要執行一次,那麼這個模式就很是有用。
 * 由於並無任何理由去執行本能夠避免的重複工做,即該函數的一些部門可能並再也不須要。
 * 在這種狀況下,自定義函數能夠更新自身的實現。使用此模式能夠顯著地幫助提高應用程序的性能,
 * 這是因爲從新定義的函數僅執行了更少的工做。
 */
var scareMe = function () {
    alert('Boo!');
    scareMe = function () {
        alert('Double boo!');
    };
}

scareMe();    //Boo!
scareMe();    //Double boo!
scareMe();    //Double boo!
相關文章
相關標籤/搜索