《JavaScript设计模式与开发实践》读书笔记

设计模式

单例模式

JS的单例模式有别于传统面向对象语言的单例模式,js做为一门无类的语言。使用全局变量的模式来实现单例模式思想。js里面的单例又分为普通单例和惰性单例,惰性单例指的是只有这个实例在须要被建立的时候才会被建立,建立后将始终保持这一个实例。算法

var getSingle = function (fn) {
    var result;
    return function () {
        return result || (result = fn.apply(this, arguments));
    }
};

策略模式

定义:定义一系列的算法,把它们一个个的封装起来,而且使他们能够相互替换。

策略模式至少由两部分组成:第一个部分是一组策略类,用来封装具体的算法,并负责计算过程;第二个部分是环境类,用于接受请求,并把请求委托给某一个策略类。策略模式,顾名思义就是指封装一组组特定的算法,这些算法目的相同,用来实现不一样条件下的特定要求。使用策略模式的优势在于逻辑复用,代码干净,减小多重条件判断语句的使用。好比:设计模式

const strategies = {
    S: (salary) => {
        return salary * 4;
    },
    A: (salary) => {
        return salary * 3;
    },
    B: (salary) => {
        return salary * 2;
    }
}

const calculateBouns = (key, salary) => {
    return strategies[key] && strategies[key](salary);
}

calculateBouns('S', 10000);

代理模式

虚拟代理

虚拟代理在不改变原有函数(对象)的方法结构的前提下,定义新的对象,而且实现一样的接口,给被代理函数赋予额外的行为与逻辑,作一些过滤、合并、预处理等操做。api

var myImage = (function () {
    var imgNode = document.createElement('img');
    document.body.appendChild(imgNode);

    return function (src) {
        imgNode.src = src;
    }
})();

var proxyImage = (function () {
    var img = new Image;
    img.onload = function () {
        myImage(this.src);
    };

    return function (src) {
        myImage('loading.gif');
        img.src = src;
    };
})();

缓存代理

缓存代理能够为一些开销大的运算结果提供暂时的缓存(适用纯函数模式),在下次运算时,若是传递的参数和以前保持一致,则直接返回以前存储的运算结果。
var createProxyFactory = function (fn) {
    var cache = {};
    return function () {
        var args = Array.prototype.join.call(arguments, ',');
        if (args in cache) {
            return cache[args];
        }
        return cache[args] = fn.apply(this, arguments);
    }
}

迭代器模式

相似数组的遍历...数组

发布订阅模式

发布订阅模式是一种典型的推模式,即主动向用户推送数据的方式。通常的函数调用都是拉模式,即用户主动获取数据。订阅模式的一个典型的应用就是rxjs(后面会写一篇相关的读书笔记)。书中给出了一个最终版的代码,但也是存在必定的局限性,具体实现须要按需解决。缓存

var Event = (function () {
    var global = this, Event, _default = 'default';

    Event = function () {
        var _listen,
            _trigger,
            _remove,
            _slice = Array.prototype.slice,
            _shift = Array.prototype.shift,
            _unshift = Array.prototype.unshift,
            namespaceCache = {},
            _create,
            find,
            // each方法绑定函数做用域为当前数组项
            each = function (ary, fn) {
                var ret;
                for (var i = 0, l = ary.length; i < l; i++) {
                    var n = ary[i];
                    ret = fn.call(n, i, n);
                }
                return ret;
            };

        _listen = function (key, fn, cache) {
            if (!cache[key]) {
                cache[key] = [];
            }
            cache[key].push(fn);
        };

        _remove = function (key, cache, fn) {
            if (cache[key]) {
                if (fn) {
                    for (var i = cache[key].length; i >= 0; i--) {
                        if (cache[key][i] === fn) {
                            cache[key].splice(i, 1);
                        }
                    }
                } else {
                    cache[key] = [];
                }
            }
        };

        _trigger = function () {
            var cache = _shift.call(arguments),
                key = _shift.call(arguments),
                args = arguments,
                _self = this,
                ret,
                stack = cache[key];

            if (!stack || !stack.length) {
                return;
            }

            return each(stack, function () {
                return this.apply(_self, args);
            });
        };

        _create = function (namespace) {
            var namespace = namespace || _default;
            var cache = {},
            offlineStack = [],
            ret = {
                listen: function (key, fn, last) {
                    _listen(key, fn, cache);
                    if (offlineStack === null) {
                        return;
                    }
                    if (last === 'last') {
                        offlineStack.length && offlineStack.pop()();
                    } else {
                        each(offlineStack, function () {
                            this();
                        });
                    }
                    offlineStack = null;
                },
                one: function (key, fn, last) {
                    _remove(key, cache);
                    this.listen(key, fn, last);
                },
                remove: function (key, fn) {
                    _remove(key, cache, fn);
                },
                trigger: function () {
                    var fn, args, _self = this;

                    _unshift.call(arguments, cache);
                    args = arguments;

                    fn = function () {
                        return _trigger.apply(_self, args);
                    };

                    if (offlineStack) {
                        return offlineStack.push(fn);
                    }

                    return fn();
                }
            };

            return namespace ?
                (namespaceCache[namespace] ? namespaceCache[namespace] : namespaceCache[namespace] = ret)
                    : ret;
        };

        return {
            create: _create,
            one: function (key, fn, last) {
                var event = this.create();
                event.one(key, fn, last);
            },
            remove: function (key, fn) {
                var event = this.create();
                event.remove(key, fn);
            },
            listen: function (key, fn, last) {
                var event = this.create();
                event.listen(key, fn, last);
            },
            trigger: function () {
                var event = this.create();
                event.trigger.apply(this, arguments);
            }
        };
    }();

    return Event;
})();

命令模式

定义一系列的算法,功能不一样,将他们聚合成一个总体,做为命令接受者,再定义一个中间函数,用来根据不一样的指令调用接受者对象。而实际命令对象只须要来调用这个中间函数而无需直接和接受者交互。命令模式适用于逻辑撤销逻辑回放的操做。app

组合模式

在父子链的函数上面实现相同的接口,在函数调用层面接口保持一致,具体函数逻辑各自独立。组合模式可让咱们使用树形方式建立对象的结构。咱们能够把相同的操做应用在组合对象和单个对象上。函数

模板方法模式

定义一系列api执行流程,相同部分由父函数实现,不一样部分api里面的具体操做交由传入的函数决定。在js里面,会更多的去使用高阶函数去替代。性能

享元模式

享元模式的核心思想是对象复用,减小对象数量,减小内存开销。this

职责链模式

职责链模式的核心思想是,一个函数,分为两个部分,一部分:在符合条件的状况下,处理业务并结束传递;另一部分,不符合条件,将业务处理转交给下一个函数,至于下个函数是谁,经过传递参数或者暴露接口来决定,而不是在函数内部写死。下降函数耦合性。
职责链的优势是下降函数复杂度,缺点是过长的职责链可能会形成多段代码闲置。可能不少中间链只起到传递参数的做用,下降了性能。spa

中介者模式

一些相互关联的对象,对象与对象之间隔绝联系,而且建立一个中间对象,将这些对象之间的联系与关联放在中间对象里面来处理。减小代码耦合。

装饰者模式

装饰者模式与代理模式相似,即在执行目标函数以前或者后进行一些额外的操做,与代理模式的区别在于,装饰者模式所作的操做不必定与目标函数是一个类型的,所实现的功能也多是千差万别的。

状态模式

定义:容许一个对象在其内部状态改变时改变他它的行为,对象看起来彷佛修改了它的类。
状态模式在其内部包含了多种转态对象,这些状态对象有着类似的api,在调用这些api的时候,会动态修改状态模式的当前状态。从而是状态类的同一个api作出不一样的反应。

适配器模式

对目标函数进行数据参数转化,使其符合目标函数所须要的格式。

设计原则

单一职责原则

一个对象只作一件事情。

最少知识原则

一个软件实体应当尽量少的与其余实体发生相互做用。

开放-封闭原则

当须要改变一个程序的功能或者给这个程序增长新功能的时候,可使用增长代码的方式,可是不容许改动程序的源代码。
相关文章
相关标签/搜索