资讯专栏INFORMATION COLUMN

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

Panda / 1746人阅读

摘要:订阅模式的一个典型的应用就是后面会写一篇相关的读书笔记。享元模式享元模式的核心思想是对象复用,减少对象数量,减少内存开销。适配器模式对目标函数进行数据参数转化,使其符合目标函数所需要的格式。

设计模式 单例模式

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);
代理模式 虚拟代理

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

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;
})();
命令模式

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

组合模式

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

模板方法模式

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

享元模式

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

职责链模式

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

中介者模式

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

装饰者模式

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

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

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

设计原则 单一职责原则
一个对象只做一件事情。
最少知识原则
一个软件实体应当尽可能少的与其他实体发生相互作用。
开放-封闭原则
当需要改变一个程序的功能或者给这个程序增加新功能的时候,可以使用增加代码的方式,但是不允许改动程序的源代码。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/97777.html

相关文章

  • JavaScript 设计模式开发实践读书笔记

    摘要:设计模式与开发实践读书笔记最近利用碎片时间在上面阅读设计模式与开发实践读书这本书,刚开始阅读前两章内容,和大家分享下我觉得可以在项目中用的上的一些笔记。事件绑定暂时这么多,以后会不定期更新一些关于我读这本书的笔记内容 JavaScript 设计模式与开发实践读书笔记 最近利用碎片时间在 Kindle 上面阅读《JavaScript 设计模式与开发实践读书》这本书,刚开始阅读前两章内容,...

    FingerLiu 评论0 收藏0
  • 代码书写优化(javaScript设计模式开发实践--读书笔记

    摘要:独立出来的函数更加容易被改写,减少维护成本。例如一个分页函数,函数接受一个表示挑战页码,在跳转前需要判断是否在有效的取值范围。面向对象设计鼓励将行为分布在合理数量的更小对象之中。 这是《 javaScript设计模式与开发实践 》一书的最后一章代码重构。 以下的一些方法不是必须严格遵守的标准,选择实践哪些,以及如何实现这都需根据情况而定(是不是有充足时间) 提炼函数 如果在函数中有一...

    geekidentity 评论0 收藏0
  • 《高性能JavaScript读书笔记

    摘要:除此以外,让元素脱离文档流也是一个很好的方法。因为元素一旦脱离文档流,它对其他元素的影响几乎为零,性能的损耗就能够有效局限于一个较小的范围。讲完重排与重绘,往元素上绑定事件也是引起性能问题的元凶。高性能这本书非常精致,内容也非常丰富。 showImg(https://segmentfault.com/img/bVJgbt?w=600&h=784); 入手《高性能JavaScript》一...

    W_BinaryTree 评论0 收藏0
  • 《编写可维护的 JavaScript读书笔记

    摘要:最近阅读了编写可维护的,在这里记录一下读书笔记。禁止使用,,,的字符串形式。避免使用级事件处理函数。让事件处理程序成为接触到对象的唯一函数。检测函数是检测检测函数的最佳选择。为特定浏览器的特性进行测试,并仅当特性存在时即可应用特性检测。 最近阅读了《编写可维护的 JavaScript》,在这里记录一下读书笔记。书中主要基于三个方向来讲解怎么增加代码的可维护性:编程风格、编程实践、自动化...

    tuniutech 评论0 收藏0
  • javascript 的 eval()——编写可维护的javascript读书笔记

    摘要:尽管在类库中,可能会经常用到通常和操作有关,另外三种用法即使也非常罕见。一个通用的原则是,禁止使用,并且只在别无他法时使用,。和也是可以使用的,但不要用字符串形式而要用函数 再javascript中,eval()的参数是一个字符串,eval()会将传入的字符串当做代码来执行,开发者可以通过这个函数来载入外部的javascript代码,活着随机生成Javascript代码并执行它,比如:...

    lemon 评论0 收藏0

发表评论

0条评论

Panda

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<