【读书笔记】读《JavaScript模式》 - JavaScript函数常用模式

  API模式:回调模式、配置对象、返回函数;

  初始化模式:即时函数、即时对象初始化、初始化分支;

  性能模式:备忘模式、自定义模式

 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!

 

 

 

 

 

posted @ 2013-12-17 00:04  金广国  阅读(331)  评论(0编辑  收藏  举报