资讯专栏INFORMATION COLUMN

JavaScript 设计模式

JayChen / 1906人阅读

摘要:应用场景一个的构造函数,提供创建不同类型汽车的方法。优点保护全局命名空间免受污染,能很快地找到相应的构造函数。如果构造函数不存在,报错原型继承父类,且只继承一次迭代器模式定义按顺序访问一个聚合对象中各个元素。

1. 单例模式

定义:一个特定类 仅有一个实例

应用场景: 一个遮罩层

实现方式

每个对象都是一个单体,因为他们的引用位置不一样;

使用new操作符

将首次生成的对象存储在全局变量中。缺点:全局变量易被覆盖。可以使用闭包来存储这个变量,参见 一个遮罩层。

在构造函数的属性中存储该实例。缺点:构造函数的属性也容易被修改。

        function Universe() {
            if (typeof Universe.instance === "object") {
                return Universe.instance
            }

            this.start_time = 0;
            this.bang = "Big";

            Universe.instance = this;
        }

        var uni1 = new Universe();
        var uni2 = new Universe();

        console.log(uni1 === uni2); // true    
    - 重写构造函数,使用闭包来储存这个实例。缺点:
//缺点: 这种方式会丢掉初始实例与重写构造函数之间的关系,因此后面再向重写的构造函数原型中添加属性时,并不会添加到初始实例中去。
        function Universe() {
            var instance = this;
            this.start_time = 0;
            this.bang = "Big";

            Universe = function Universe() {
                return instance;
            }
        }

        Universe.prototype.nothing = true;
        var uni1 = new Universe();

        Universe.prototype.everything = true;
        var uni2 = new Universe();

        console.log(uni1 === uni2); //true
        console.log(uni1.nothing); //true
        console.log(uni2.nothing); //true
        console.log(uni1.everything); //undefined
        console.log(uni2.everything); //undefined    
        console.log(uni1.constructor === Universe); //false

因此,我们需要先重写构造函数、保留原型属性、生成实例,返回实例。

        function Universe() {
            var instance;
            
            Universe = function () {
                return instance;
            }

            Universe.prototype = this;

            instance = new Universe();
            instance.constructor = Universe;

            this.start_time = 0;
            this.bang = "big";

            return instance;
        }

        Universe.prototype.nothing = true;
        var uni1 = new Universe();

        Universe.prototype.everything = true;
        var uni2 = new Universe();

        console.log(uni1 === uni2); //true
        console.log(uni1.nothing); //true
        console.log(uni2.nothing); //true
        console.log(uni1.everything); //true
        console.log(uni2.everything); //true
        console.log(uni1.constructor === Universe); //true
- 还有一种就是使用即时函数
        var Universe;
        (function () {
            var instance;
            Universe =     function () {
                if (instance) {
                    return instance;
                }

                instance = this;
                this.start_time = 0;
                this.bang = "big";
            }
        })();

        Universe.prototype.nothing = true;
        var uni1 = new Universe();

        Universe.prototype.everything = true;
        var uni2 = new Universe();

        console.log(uni1 === uni2); //true
        console.log(uni1.nothing); //true
        console.log(uni2.nothing); //true
        console.log(uni1.everything); //true
        console.log(uni2.everything); //true
        console.log(uni1.constructor === Universe); //true    
2. 工厂模式

定义: 提供创建相似对象的可重用方法。在不确定的情况下,提前提供一种创建某类的方法。总-分模式。

应用场景:一个CarMaker的构造函数,提供创建不同类型汽车的factory方法。

实现方式。优点:保护全局命名空间免受污染,能很快地找到相应的构造函数。

        function CarMaker() {}
        
        CarMaker.prototype.getPrice =     function () {
            console.log("Price:", this.price);
        }

        CarMaker.factory = function (type) {
            var newcar;
            //如果构造函数不存在,报错
            if (typeof CarMaker[type] !== "function") {
                throw {
                    name: "Error",
                    message: type + " dosen"t exist"
                }
            }

            //原型继承父类,且只继承一次
            if (typeof CarMaker[type].prototype.getPrice !== "function") {
                CarMaker[type].prototype = new CarMaker();
            }

            newcar = new CarMaker[type]();
            return newcar;
        }

        CarMaker.SUV = function () {
            this.price = 100;
        }

        CarMaker.Compat = function () {
            this.price = 50;
        }

        var a = CarMaker.factory("SUV");
        var b = CarMaker.factory("Compat");

        a.getPrice(); //Price: 100
        b.getPrice(); //Price: 100
3. 迭代器模式

定义:按顺序访问一个聚合对象中各个元素。通常包含next(获取下一个元素), hasNext(是否到末尾),rewind(重置初始位置), current(当前元素)集中方法。

应用场景:需要按照顺序,以不同的间隔获取集合中的元素。

实现方法:

function iterator (data = [], gap = 1) {
         var index = 0, //记录当前位置
                 length = data.length; //数据总长度
         return {
             next() {
                 var element;
                 if (!this.hasNext()) {
                     return null;
                 }
                 element = data[index];
                 index += gap;
                 return element;
             },
             hasNext() {
                 return index < length;
             },
             rewind() {
                 index = 0;
             },
             current() {
                 return data[index];
             }
         }
     }

     var arrIterator = iterator([1, 2, 3, 4, 5]);

     while(arrIterator.hasNext()) {
         console.log(arrIterator.next());
     }

     arrIterator.rewind();
     console.log(arrIterator.current());
4. 装饰者模式

定义: 在运行时动态添加附加功能到对象中。

应用场景:购买某种东西时,随着添加不同的装备,价格也不一样。最后需要根据添加的设备计算总价。

实现方法:要注意的是,各装饰器需要提供原型方法的接口。 另一种实现方式

        function Sale(price = 100) {
            this.price = price;
            this.decorators_list = [];
        }

        //装饰器
        Sale.decorators = {};
        Sale.decorators.pack = {
            getPrice(price) {
                return price + 20;
            }
        }
        Sale.decorators.mail = {
            getPrice(price) {
                return price + 10;
            }
        }

        Sale.prototype.decorate = function (decorator) {
            this.decorators_list.push(decorator);
        }

        Sale.prototype.getPrice = function () {
            let price = this.price;
            //调用各装饰器的接口
            for (let i = 0, len = this.decorators_list.length; i < len; i++) {
                name = this.decorators_list[i];
                price = Sale.decorators[name].getPrice(price);
            }
            return price;
        }

        var sale = new Sale();
        sale.decorate("pack");
        sale.decorate("mail");
        console.log(sale.getPrice()); //130
5. 策略者模式

定义:在运行时可以选择算法。

应用场景:表单验证。

实现方式:一个含有config(配置验证规则), types(验证类型), validate(验证方法), message(结果消息数组), hasErrors(最后结构)几个属性的validator对象。

6. 外观模式

定义:提供一个高级接口,调用经常需要同时使用的几个基础方法。

应用场景:将stopPropagationpeventDefault包装在stop这个高级接口中。

饭堂的炒菜师傅不会因为你预定了一份烧鸭和一份白菜就把这两样菜炒在一个锅里。他更愿意给你提供一个烧鸭饭套餐。同样在程序设计中,我们需要保证函数或者对象尽可能的处在一个合理粒度,毕竟不是每个人喜欢吃烧鸭的同时又刚好喜欢吃白菜。

外观模式还有一个好处是可以对用户隐藏真正的实现细节,用户只关心最高层的接口。比如在烧鸭饭套餐的故事中,你并不关心师傅是先做烧鸭还是先炒白菜,你也不关心那只鸭子是在哪里成长的。

7. 代理模式

定义:介于对象和对象的客户端之间,对对象本体起保护作用,使本体对象做尽可能少的工作。目的是解决性能问题。

应用场景:

初始化本体对象消耗非常大,但是在初始化该对象的之后并未使用。此时可使用代理模式,接收初始化请求,返回ok,等真正用到本体对象时再初始化。

发起Http请求会消耗性能,最好的方法就是使用代理合并Http请求,比如将50ms内的发起的请求合并为一个请求。

为了减少性能消耗,还可给代理设置一个缓存,缓存结果。

fragment应该就算一个代理模式吧,缓存了对DOM的操作。

实现方法:对象客户端调用代理提供的方法,代理对客户端的请求进行处理后调用对象本体方法。

8. 中介者模式

定义:一个程序中有很多对象,这些对象之间会相互通信。但是如果修改其中一个对象,则必然会牵涉到其他和他通信的对象,造成紧耦合。中介者模式就是提出一个中间对象来实现对象间的松耦合通信。通信的对象不用知道对方是谁,只要有变动就通知给这个中介者,中介者知道所有的对象并且负责联系相应的对象做出处理。

应用场景:MVC中的Controller

实现方法:http://www.jspatterns.com/boo...

9. 观察者模式

定义:该模式的目的也是为了形成松耦合。对象之间不直接调用彼此的方法,而是采取订阅的模式,订阅者订阅发布者的事件,并向发布者提供一个事件发生时调用的方法。中介者模式中的mediator需要知道所有其他对象,而该模式并不需要知道,只要订阅事件即可。

应用场景:DOM中的事件。

实现方法:
发布者需要:订阅者的列表{type: []},订阅方法, 取消订阅,发布消息几种方法。http://www.jspatterns.com/boo...

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

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

相关文章

  • JS程序

    摘要:设计模式是以面向对象编程为基础的,的面向对象编程和传统的的面向对象编程有些差别,这让我一开始接触的时候感到十分痛苦,但是这只能靠自己慢慢积累慢慢思考。想继续了解设计模式必须要先搞懂面向对象编程,否则只会让你自己更痛苦。 JavaScript 中的构造函数 学习总结。知识只有分享才有存在的意义。 是时候替换你的 for 循环大法了~ 《小分享》JavaScript中数组的那些迭代方法~ ...

    melody_lql 评论0 收藏0
  • 2017年 最好的javascript 书籍

    摘要:请记住,这些书中的一些可能不是最新的,但概念和基础仍应适用。是最好的老师之一。的秘密由部分组成。在你完成这些书后,查看书籍和最好的本土书籍。 我看过三本,第1本,第二本,第四本。第一本买的的实体书,其他两本看的是电子书。第一本是大名鼎鼎老道写的,书很薄,但是非常经典。javascirpt忍者秘籍是jquery的作者写的,也是非常经典。you dont kown js系列也是非常好。看了...

    mingzhong 评论0 收藏0
  • 前端练级攻略(第二部分)

    摘要:是文档的一种表示结构。这些任务大部分都是基于它。这个实践的重点是把你在前端练级攻略第部分中学到的一些东西和结合起来。一旦你进入框架部分,你将更好地理解并使用它们。到目前为止,你一直在使用进行操作。它是在前端系统像今天这样复杂之前编写的。 本文是 前端练级攻略 第二部分,第一部分请看下面: 前端练级攻略(第一部分) 在第二部分,我们将重点学习 JavaScript 作为一种独立的语言,如...

    BWrong 评论0 收藏0
  • 理解JavaScript的核心知识点:原型

    摘要:首先,需要来理清一些基础的计算机编程概念编程哲学与设计模式计算机编程理念源自于对现实抽象的哲学思考,面向对象编程是其一种思维方式,与它并驾齐驱的是另外两种思路过程式和函数式编程。 JavaScript 中的原型机制一直以来都被众多开发者(包括本人)低估甚至忽视了,这是因为绝大多数人没有想要深刻理解这个机制的内涵,以及越来越多的开发者缺乏计算机编程相关的基础知识。对于这样的开发者来说 J...

    iKcamp 评论0 收藏0
  • JavaScript系列(四) - 收藏集 - 掘金

    摘要:函数式编程前端掘金引言面向对象编程一直以来都是中的主导范式。函数式编程是一种强调减少对程序外部状态产生改变的方式。 JavaScript 函数式编程 - 前端 - 掘金引言 面向对象编程一直以来都是JavaScript中的主导范式。JavaScript作为一门多范式编程语言,然而,近几年,函数式编程越来越多得受到开发者的青睐。函数式编程是一种强调减少对程序外部状态产生改变的方式。因此,...

    cfanr 评论0 收藏0
  • JavaScript进阶之路

    摘要:前端入门的门槛相对较低,学习曲线是越来越陡峭,由浅入深,可以分为四个阶段。第二阶段高级程序设计有的书是用来成为经典的,比如犀牛书还有些书是用来超越经典的,显然这本书就是。接下来可以看看教程,看看源代码,尝试着写一写这些效果。 前端入门的门槛相对较低,学习曲线是越来越陡峭,由浅入深,可以分为四个阶段。 第一阶段:《JavaScript DOM编程艺术》    看这本书之前,请先确认你对J...

    Lowky 评论0 收藏0

发表评论

0条评论

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