目录
单例模式
特点
应用
实例
构造函数模式
原型模式
混合模式
工厂模式
简单工厂模式
迭代器模式
策略模式
外观模式
作用
代理模式
虚拟代理
图片懒加载
合并http请求
缓存代理
优缺点
模块模式
首页 web前端 js教程 JS常用设计模式

JS常用设计模式

Feb 23, 2018 pm 03:14 PM
javascript 常用 设计模式

大型单页应用里,复杂度上升到一定程度时,没有适当的设计模式进行降耦,后续的开发也难以下手。
而设计模式正是为了降耦而存在。

单例模式

单例模式的核心是确保只有一个实例,并且提供全局访问。

特点

满足“单一职责原则” : 使用代理模式,不在构造函数中判断是否已经创建过该单例;

满足惰性原则

应用

弹出登陆窗口。

实例

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

var createPopup() {
    var p = document.createElement('p');
    p.innerHTML = "Login window";
    p.style.display = "none"; 
    document.body.appendChild(p);
    return p;
}

var createLoginPopup = getSingle(createPopup);            
//create popup p here by using a given function, 满足两个原则 

document.getElementById("loginBt").onclick = function() {
    var popup = createLoginPopup();
    pop.style.display = "block";
}
登录后复制

构造函数模式

/**
 * 构造一个动物的函数 
 */
function Animal(name, color){
    this.name = name;
    this.color = color;
    this.getName = function(){
        return this.name;
    }
}
// 实例一个对象
var cat = new Animal('猫', '白色');
console.log( cat.getName() );
登录后复制

原型模式

function Person(){  
}

Person.prototype.name = "bill";
Person.prototype.address = "GuangZhou";
Person.sayName = function (){
    alert(this.name);  
}

var person1 = new Person();
var person2 = new Person();
 
//测试代码
alert(person1.name);   // bill
alert(person2.name);    // bill
person1.sayName();    //bill
person2.sayName();    //bill

person1.name = "666";

alert(person1.name);   // 666
alert(person2.name);    // bill
person1.sayName();    //666
person2.sayName();    //bill
登录后复制

混合模式

/**
 * 混合模式 = 原型模式 + 构造函数模式
 */
function Animal(name, color){
    this.name = name;
    this.color = color;

    console.log( this.name  +  this.color)
}
Animal.prototype.getInfo = function(){
    console.log('名称:'+ this.name);
}

function largeCat(name, color){
    Animal.call(null, name, color);

    this.color = color;
}

largeCat.prototype = create(Animal.prototype);
function create (parentObj){
    function F(){}
    F.prototype = parentObj;
    return new F();
};

largeCat.prototype.getColor = function(){
    return this.color;
}
var cat = new largeCat("Persian", "白色");
console.log( cat )
登录后复制

工厂模式

工厂:函数内部产生b对象并返回。

1. 
function a(name){
  var b = new object();
    b.name = name;
    b.say = function(){
        alert(this.name);
    }   
       return b    
}
2. 
function Animal(opts){
    var obj = new Object();
    obj.name = opts.name;
    obj.color = opts.color;
    obj.getInfo = function(){
        return '名称:'+obj.name +', 颜色:'+ obj.color;
    }
    return obj;
}
var cat = Animal({name: '波斯猫', color: '白色'});
cat.getInfo();
登录后复制

简单工厂模式

简单工厂模式的理念就是创建对象,对不同类的实例化;只需要创建一个对象,然后通过对这个对象大量的方法和属性,并在最终将对象返回出来

//basketball base class  
var Baseketball = function(){  
  this.intro = 'baseketball is hotting at unitedstates';  
}  
Baseketball.prototype = {  
  getMember : function(){\  
    console.log('each team needs five players');  
  },  
  getBallSize : function(){  
    console.log('basketball is big');  
  }  
}  
//football base class   
var Football = function(){  
  this.intro = 'football is popular at all of the world';  
}  
Football = function(){  
  getMember = function(){  
  
  },  
  getBallSize = function(){  
  
  }  
}  
//sport factory  
var SportsFactory = function(name){  
  switch(name){  
    case 'NBA':  
      return new Baseketball();  
    case 'wordCup':  
      return new Football();  
  }  
}  
  
//when you want football   
var football = SportsFactory('wordCup');  
console.log(football);  
console.log(football.intro);  
football.getMember();
登录后复制

迭代器模式

装饰者模式

策略模式

定义一个个可以相互替换的算法,并且把他们封装起来。

特点

  1. 符合开放-封闭原则 : 要修改使用的算法时不用深入函数内部进行修改,只需修改策略类;

  2. 将算法的实现与使用分离开,提高算法复用性;

  3. 通过组合、委托和多态避免多重条件选择语句;

应用

动画实现不同的缓动效果。

一般分为两个部分:策略类于环境类。策略类用于封装各种算法,并且负责具体的计算过程; 环境类负责接收用户的请求,并且把请求委托给某一个策略类。因为各个策略类实现的算法和计算的结果不同,而环境类调用策略类的方法却是相同的,这就体现了多态性。要想实现不同的算法,只需要替换环境类中的策略类即可。

在js中,我们不必构造策略类,可直接使用函数作为策略对象。

示例

var strategies = {
    "s1": function() {
        //algo 1
    },
    "s2": function() {
        //algo 2
    }, 
    "s3": function() {
        //algo 3
    }
 }
 
 var someContext =  new SomeConext();
 someContext.start("s1");  //using s1 to calculate
 //someContext.add("s1");  or add s1 as a rule for validation
登录后复制

外观模式

也可译为门面模式。它为子系统中的一组接口提供一个一致的界面, Facade模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。引入外观角色之后,使用者只需要直接与外观角色交互,使用者与子系统之间的复杂关系由外观角色来实现,从而降低了系统的耦合度。
比如在家要看电影,需要打开音响,再打开投影仪,再打开播放器等等,引入外观角色之后,只需要调用“打开电影设备”方法就可以。外观角色封装了打开投影仪等操作,给使用者提供更容易使用的方法。

作用

  1. 简化复杂接口

  2. 解耦和,屏蔽使用者对子系统的直接访问

实例

在形式上,外观模式在javascript中就像这样:

function a(x){
   // do something
}
function b(y){
   // do something
}
function ab( x, y ){
    a(x);
    b(y);
}
登录后复制

下面的一个例子,把阻止冒泡和阻止默认事件放到了外观角色中:

var N = window.N || {};

N.tools = {
    stopPropagation : function( e ){
        if( e.stopPropagation ){
            e.stopPropagation();
        }else{
            e.cancelBubble = true;
        }
    },

    preventDefault : function( e ){
        if( e.preventDefault ){
            e.preventDefault();
        }else{
            e.returnValue = false;
        }
    },
    
    stopEvent : function( e ){
        N.tools.stopPropagation( e );
        N.tools.preventDefault( e );
    }
登录后复制

外观模式在javascript的应用主要可以分为两类,某块代码反复出现,比如函数a的调用基本都出现在函数b的调用之前,那么可以考虑考虑将这块代码使用外观角色包装一下来优化结构。还有一种就是对于一些浏览器不兼容的API,放置在外观内部进行判断,处理这些问题最好的方式便是将跨浏览器差异全部集中放置到一个外观模式实例中来提供一个对外接口。

代理模式

代理模式的定义:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。

虚拟代理

虚拟代理是把一些开销很大的对象,延迟到真正需要它的时候才去创建执行

图片懒加载

//图片加载
let imageEle = (function(){
    let node = document.createElement('img');
    document.body.appendChild(node);
    return {
        setSrc:function(src){
            node.src = src;
        }
    }
})();

//代理对象
let proxy = (function(){
    let img = new Image();
    img.onload = function(){
        imageEle.setSrc(this.src);
    };
    return {
        setSrc:function(src){
            img.src = src;
            imageEle.setSrc('loading.gif');
        }
    }
})();

proxy.setSrc('example.png');
登录后复制

合并http请求

如果有一个功能需要频繁进行请求操作,这样开销比较大,可以通过一个代理函数收集一段时间内请求数据,一次性发出

//上传请求
let upload = function(ids){
    $.ajax({
        data: {
            id:ids
        }
    })
}

//代理合并请求
let proxy = (function(){
    let cache = [],
        timer = null;
    return function(id){
        cache[cache.length] = id;
        if(timer) return false;
        timer = setTimeout(function(){
            upload(cache.join(','));
            clearTimeout(timer);
            timer = null;
            cache = [];
        },2000);
    }    
})();
// 绑定点击事件
let checkbox = document.getElementsByTagName( "input" );
for(var i= 0, c; c = checkbox[i++];){
    c.onclick = function(){
        if(this.checked === true){
            proxy(this.id);
        }
    }
}
登录后复制

缓存代理

缓存代理可以作为一些开销大的运算结果提供暂时的存储,下次运算时,如果传递进来的参数跟之前一致,则可以直接返回前面存储的运算结果

//计算乘积
let mult = function(){
    let result = 1;
    for(let i = 0,len = arguments.length;i < len;i++){
        result*= arguments[i];
    }
    return result;
}

//缓存代理
let proxy = (function(){
    let cache = {};
    reutrn function(){
        let args = Array.prototype.join.call(arguments,',');
        if(args in cache){
            return cache[args];
        }
        return cache[args] = mult.apply(this,arguments);
    }
})();
登录后复制

优缺点

1.优点:代理模式能将代理对象与被调用对象分离,降低了系统的耦合度。代理模式在客户端和目标对象之间起到一个中介作用,这样可以起到保护目标对象的作用。代理对象也可以对目标对象调用之前进行其他操作。
2.缺点:增加了系统的复杂度

观察者模式

模块模式

/**
 * 模块模式 = 封装大部分代码,只暴露必需接口
 */
var Car = (function(){
    var name = '法拉利';
    function sayName(){
        console.log( name );
    }
    function getColor(name){
        console.log( name );
    }
    return {
        name: sayName,
        color: getColor
    }
})();
Car.name();
Car.color('红色');
登录后复制

相关推荐:

js组合设计模式详解

php设计模式之服务定位器模式实例详解

详解PHP设计模式之委托模式

以上是JS常用设计模式的详细内容。更多信息请关注PHP中文网其他相关文章!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

Java框架中设计模式与架构模式的区别 Java框架中设计模式与架构模式的区别 Jun 02, 2024 pm 12:59 PM

在Java框架中,设计模式和架构模式的区别在于:设计模式定义了在软件设计中解决常见问题的抽象解决方案,关注类和对象之间的交互,如工厂模式。架构模式定义了系统结构和模块之间的关系,关注系统组件的组织和交互,如分层架构。

Java设计模式之装饰器模式剖析 Java设计模式之装饰器模式剖析 May 09, 2024 pm 03:12 PM

装饰器模式是一种结构型设计模式,允许动态添加对象功能,无需修改原始类。它通过抽象组件、具体组件、抽象装饰器和具体装饰器的协作实现,可以灵活扩展类功能,满足变化的需求。示例中,将牛奶和摩卡装饰器添加到Espresso,总价为2.29美元,展示了装饰器模式在动态修改对象行为方面的强大功能。

PHP 设计模式实战案例解析 PHP 设计模式实战案例解析 May 08, 2024 am 08:09 AM

1.工厂模式:分离对象创建和业务逻辑,通过工厂类创建指定类型的对象。2.观察者模式:允许主题对象通知观察者对象其状态更改,实现松耦合和观察者模式。

设计模式如何应对代码维护难题 设计模式如何应对代码维护难题 May 09, 2024 pm 12:45 PM

设计模式通过提供可重用和可扩展的解决方案来解决代码维护难题:观察者模式:允许对象订阅事件,并在事件发生时收到通知。工厂模式:提供了一种创建对象的集中式方式,而无需依赖具体类。单例模式:确保一个类只有一个实例,用于创建全局可访问的对象。

Java设计模式之适配器模式的妙用 Java设计模式之适配器模式的妙用 May 09, 2024 pm 12:54 PM

适配器模式是一种结构型设计模式,允许不兼容对象协同工作,它将一个接口转换为另一个,使对象能够顺利交互。对象适配器通过创建包含被适配对象的适配器对象,并实现目标接口,实现适配器模式。在一个实战案例中,通过适配器模式,客户端(如MediaPlayer)可以播放高级格式的媒体(如VLC),尽管其本身仅支持普通媒体格式(如MP3)。

PHP设计模式:测试驱动开发实践 PHP设计模式:测试驱动开发实践 Jun 03, 2024 pm 02:14 PM

TDD用于编写高质量PHP代码,步骤包括:编写测试用例,描述预期功能并使其失败。编写代码,仅使测试用例通过,无需过分优化或详细设计。测试用例通过后,优化和重构代码以提高可读性、可维护性和可扩展性。

15个常用的币圈逃顶指标技术分析 15个常用的币圈逃顶指标技术分析 Mar 03, 2025 pm 05:48 PM

十五大比特币逃顶指标深度解析:2025年市场展望本文深入分析了十五个常用的比特币逃顶指标,其中比特币Rhodl比率、USDT活期理财和山寨币季节指数已于2024年触及逃顶区间,引发市场关注。面对潜在风险,投资者该如何应对?让我们逐一解读这些指标,并探讨合理的应对策略。一、关键指标详解AHR999囤币指标:由ahr999创建,辅助比特币定投策略。当前值为1.21,处于观望区间,建议谨慎。链接AHR999逃顶指标:AHR999囤币指标的补充,用于识别市场顶部。当前值为2.48,本周

Guice框架中设计模式的应用 Guice框架中设计模式的应用 Jun 02, 2024 pm 10:49 PM

Guice框架应用了多项设计模式,包括:单例模式:通过@Singleton注解确保类只有一个实例。工厂方法模式:通过@Provides注解创建工厂方法,在依赖注入时获取对象实例。策略模式:将算法封装成不同策略类,通过@Named注解指定具体策略。

See all articles