JS設(shè)計(jì)模式(持續(xù)更新中)

1.單例模式

定義

一個(gè)類(lèi)只產(chǎn)生唯一的實(shí)例

實(shí)現(xiàn)

  1. es5

    function Single(name) {
        this.instance = null;
        this.name = name;
        this.init();
    }
    Single.prototype.init = function() {
        console.log(this.name)
    }
    Single.getInstance = function(name) {
        if (!this.instance) {
            this.instance = new Single(name);
        }
        return this.instance;
    };
    var a = Single.getInstance('test_a')
    var b = Single.getInstance('test_b')
    console.log(a,b,a===b)
    

    這里會(huì)發(fā)現(xiàn)只打印了一次this.name,且this.nametest_a,而a和b是兩個(gè)一樣的對(duì)象

  2. es6

    class Single {
        constructor(name) {
            this.instance = null;
            this.name = name;
            this.init();
        }
        //保證可以直接引用getInstance方法,
        static getInstance(name) {
            if (!this.instance) {
             this.instance = new Single(name);
         }
             return this.instance;
        }
    }
    var a = Single.getInstance('test_a')
    var b = Single.getInstance('test_b')
    console.log(a,b,a===b)
    
  3. 惰性單例

    保證在需要的時(shí)候才創(chuàng)建對(duì)象實(shí)例

    var single = function (name) {
        console.log(name)
        return name
    };
    var getSingle = function (fn) {
        var result;
        return function () {
            return result || (result = fn.apply(this, arguments))
        }
    }
    var test = getSingle(single)
    test('test_a');
    test('test_b');
    

??

  1. 彈框

    假設(shè)一個(gè)場(chǎng)景,每次點(diǎn)擊按鈕彈出一個(gè)彈框,要通過(guò)創(chuàng)建一個(gè)div實(shí)現(xiàn),創(chuàng)建時(shí)不必每次都創(chuàng)建一個(gè)新的div

    <button id="btn">創(chuàng)建</button>
    <script>
        var single = function () {
            var div = document.createElement("div");
            div.style.border = '1px solid #000';
            div.style.width = '200px';
            div.style.height = '80px';
            document.body.appendChild(div);
            return div;
        };
        var getSingle = function (fn) {
            var result;
            return function () {
                return result || (result = fn.apply(this, arguments))
            }
        }
        var createSingle = getSingle(single);
        document.getElementById("btn").onclick = function () {
            var div = createSingle();
            //div.style
        }
    </script>
    
  1. 驗(yàn)證

    一般經(jīng)常寫(xiě)react項(xiàng)目,這中場(chǎng)景很少會(huì)遇到,我在想,做一些信息驗(yàn)證的時(shí)候是不是可以用到這種模式。

    假設(shè)我有很多地方有同樣的邏輯,例如驗(yàn)證一部分信息,當(dāng)然可以調(diào)用一個(gè)公共的函數(shù),可是如果是一個(gè)異步的邏輯,用到Promise,每次都要new Promise,這樣在相同的條件下就可以執(zhí)行一次new Promise就可以了。

    class Verify {
        constructor() {
            this.instance = null;
            this.conditions = null;
        }
        static getInstance(conditions) {
            // 驗(yàn)證條件
            if (this.conditions !== conditions) {
                this.conditions = conditions;
                this.instance = new Promise(function (resolve, reject) {
                    //...
                })
            }
            return this.instance;
        }
    }
    // 其他地方調(diào)用
    let promise = Verify.getInstance(/*conditions*/);
    promise.then((res) => {
        //...
    })
    

2.工廠模式

定義

簡(jiǎn)單工廠:由一個(gè)工廠對(duì)象決定創(chuàng)建某一產(chǎn)品對(duì)象類(lèi)的實(shí)例

工廠方法:對(duì)產(chǎn)品類(lèi)抽象,創(chuàng)建多產(chǎn)品類(lèi)的實(shí)例

抽象工廠:對(duì)類(lèi)的工廠抽象,創(chuàng)建產(chǎn)品類(lèi)簇,不會(huì)創(chuàng)建某一類(lèi)產(chǎn)品實(shí)例

實(shí)現(xiàn)

  1. 簡(jiǎn)單工廠模式

    假如有很多類(lèi)很類(lèi)似,可以分為一類(lèi),我們就可以用簡(jiǎn)單工廠模式解決

    var Apple = function() {
        this.name = 'Apple';
    }
    Apple.prototype = {
        eat:function() {
            //...
        }
    }
    var Banana = function() {
        this.name = 'Banana';
    }
    Banana.prototype = {
        eat:function() {
            //...
        }
    }
    //定義一個(gè)水果工廠
    var Fruit = function(name) {
        switch(name){
            case 'apple':
                return new Apple();
            case 'banana':
                return new Banana();
        }
    }
    //當(dāng)需要某個(gè)具體對(duì)象時(shí),調(diào)用水果工廠就可以
    var apple = Fruit('apple')
    
  2. 工廠方法模式

    var Fruit = function(type) {
        //第一次進(jìn)入時(shí)this是window
        if(this instanceof Fruit) {
            var fruit = new this[type]();
            return fruit;
         } else {
            return new Fruit(type);
         }
    }
    //工廠方法函數(shù)的原型中創(chuàng)建對(duì)象
    Fruit.prototype = {
         Apple: function() {
           this.name = "Apple",
           this.eat = function() {/* ... */}
         },
         Banana: function() {
           this.name = "Banana",
           this.eat = function() {/* ... */}
         },
    }
    var apple = Fruit('Apple');
    

    使用工廠方法模式,產(chǎn)品類(lèi)就變成了抽象類(lèi)。每次創(chuàng)建新的產(chǎn)品類(lèi)只需要修改工廠函數(shù)的原型。

  3. 抽象工廠模式

    所謂抽象,就是父類(lèi)抽象共同方法特性,但是具體實(shí)現(xiàn)由每個(gè)子類(lèi)去實(shí)現(xiàn)該方式。

    let Food = function(subType, superType) {
         //是否存在抽象類(lèi)
         if(typeof Food[superType] === 'function') {
            //緩存類(lèi)
         function F() {};
         //繼承父類(lèi)屬性和方法
         F.prototype = new Food[superType] ();
         //將子類(lèi)的constructor指向子類(lèi)
         subType.constructor = subType;
         //子類(lèi)原型繼承父類(lèi)
         subType.prototype = new F();
         } else {
             throw new Error('抽象類(lèi)不存在!')
         }
    }
    
    Food.Fruit = function() {
         this.type = 'fruit';
    }
    Food.Fruit.prototype = {
         eat: function() {
           return new Error('抽象方法不能調(diào)用');
         }
    }
    
    //水果子類(lèi)
    function Fruit(name) {
         this.name = name;
    }
    //抽象工廠實(shí)現(xiàn)WechatUser類(lèi)的繼承
    Food(Fruit, 'Fruit');
    //重寫(xiě)抽象方法
    Fruit.prototype.eat = function() {
      //...
    }
    
    let apple = new Fruit('apple');
    
  4. 比較

    工廠方法是對(duì)簡(jiǎn)單工廠的抽象

    抽象工廠是在工廠方法的基礎(chǔ)上進(jìn)一步抽象

??

暫時(shí)想到對(duì)于功能相似組件的封裝,(動(dòng)態(tài)判斷加載不同的組件、樣式,角色權(quán)限,頁(yè)面路由等等)可以用簡(jiǎn)單的工廠模式。一般不會(huì)用到抽象工廠。

3.建造者模式

定義

將一個(gè)復(fù)雜對(duì)象的構(gòu)建與它的表示分離,使同樣的構(gòu)建過(guò)程可以創(chuàng)建不同的表示。

實(shí)現(xiàn)

//定義一個(gè)肉類(lèi)
var Meat = function (name) {
    this.name = name
}
Meat.prototype.getPrice = function () {
    var price = 0;
    switch (this.name) {
        case 'Chicken':
            price = 10;
            break;
        case 'Pork':
            price = 20;
            break;
        case 'Beef':
            price = 30;
            break;
        default:
            break;
    }
    return price
}
//定義一個(gè)菜類(lèi)
var Vegetables = function (name) {
    this.name = name
}
Vegetables.prototype.getPrice = function () {
    var _this = this;
    var price = 0;
    switch (this.name) {
        case 'Cabbage':
            price = 1;
            break;
        case 'Carrots':
            price = 2;
            break;
        case 'Potatoes':
            price = 3;
            break;
        default:
            break;
    }
    return price
}
//定義食物類(lèi)
var Food = function(meat,vegetables) {
    this.meat = meat
    this.vegetables = vegetables
}
Food.prototype.getPrice = function() {
    var _this = this;
    var meat = new Meat(this.meat)
    var vegetables = new Vegetables(this.vegetables)
    return meat.getPrice() + vegetables.getPrice()
}
var food = new Food('Pork','Potatoes')
food.getPrice()

主要實(shí)現(xiàn)分布構(gòu)建一個(gè)復(fù)雜的對(duì)象,使各個(gè)部分之間相互解耦

??

實(shí)現(xiàn)一個(gè)復(fù)雜的組件,例如react中拆分組件、實(shí)現(xiàn)笛卡爾積(如上)

不同工種薪資計(jì)算:

var Human = function(name) {
    this.name = name;
}
var Work = function(work) {
    var _this = this;
    (function(){
        switch(work){
            case 'Primary':
                _this.work = 'Primary';
                _this.price = 100;
                break;
            case 'Senior':
                _this.work = 'Senior';
                _this.price = 150;
                break;
            default:
                _this.price = 0;
                break;
        }
    })(work,_this)
}
Work.prototype.getPrice = function(time) {
    return time*this.price
}
var Person = function(name,work) {
    this.name = new Human(name);
    this.work = new Work(work)
}
var person = new Person('Tom','Senior')
console.log(person.name.name)
console.log(person.work.work)
console.log(person.work.getPrice(10))

4.觀察者模式

定義

觀察者模式又稱(chēng)發(fā)布-訂閱(Publish/Subscribe)模式,定義對(duì)象間的一種一對(duì)多的依賴(lài)關(guān)系,當(dāng)一個(gè)對(duì)象的狀態(tài)發(fā)生改變時(shí),所有依賴(lài)于它的對(duì)象都將得到通知。例如dom事件,也是js和dom之間實(shí)現(xiàn)的一種觀察者模式。

實(shí)現(xiàn)

function Observer() {
    //訂閱列表
    this.subscribes = {};
}

Observer.prototype = {
    //訂閱事件
    listen: function(eventType, fn){
        var _this = this;
        if(!(eventType in _this.subscribes)) {
            _this.subscribes[eventType] = [];
        }
        _this.subscribes[eventType].push(fn);
        return this;
    },
    // 觸發(fā)事件(發(fā)布事件)
    publish: function(eventType){
        var _this = this;
        var fns = Array.prototype.slice.call(arguments,1);
        for(var i = 0; i < _this.subscribes[eventType].length; i++) {
            _this.subscribes[eventType][i].apply(_this,fns);
        }
        return this;
    },
    // 刪除訂閱事件
    remove: function(eventType, fn){
        var currentEvent = this.subscribes[eventType];
        var len = 0;
        if (currentEvent) {
            len = currentEvent.length;
            for (var i = len - 1; i >= 0; i--){
                if (currentEvent[i] === fn){
                    currentEvent.splice(i, 1);
                }
            }
        }
        return this;
    }
}
//訂閱事件A
var o = new Observer();
o.listen('test', function(data){
    console.log(data);
});
var callback = function(data) {
    console.log(data)
}
o.listen('test', callback);
o.publish('test', 'first');
o.remove('test', callback);
o.publish('test', 'second');

5.原型模式

定義

原型實(shí)例指向創(chuàng)建對(duì)象的類(lèi),創(chuàng)建新的對(duì)象可以共享原型對(duì)象的屬性和方法

實(shí)現(xiàn)

var Food = function(name) {
    this.name = name
}
Food.prototype.eat = function(){
    //...
}
var food1 = new Food('food1');
var food2 = new Food('food2');
console.log(food1.eat === food2.eat)//true


//Object.create
var food = {
    eat: function () { },
    name:''
};
// 使用Object.create創(chuàng)建
var food1 = Object.create(food);
food.name = 'food1'

如果有問(wèn)題,希望指出

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 工廠模式類(lèi)似于現(xiàn)實(shí)生活中的工廠可以產(chǎn)生大量相似的商品,去做同樣的事情,實(shí)現(xiàn)同樣的效果;這時(shí)候需要使用工廠模式。簡(jiǎn)單...
    舟漁行舟閱讀 8,110評(píng)論 2 17
  • 單例模式 適用場(chǎng)景:可能會(huì)在場(chǎng)景中使用到對(duì)象,但只有一個(gè)實(shí)例,加載時(shí)并不主動(dòng)創(chuàng)建,需要時(shí)才創(chuàng)建 最常見(jiàn)的單例模式,...
    Obeing閱讀 2,311評(píng)論 1 10
  • "use strict";function _classCallCheck(e,t){if(!(e instanc...
    久些閱讀 2,132評(píng)論 0 2
  • var navigator = navigator || {};var window = window || {}...
    DF_Sky閱讀 1,509評(píng)論 0 0
  • 找到fullcalendar.js, 找到代碼為 isRTL:false,這句話(huà) 輸入以下幾句 monthName...
    迷你小小白閱讀 1,852評(píng)論 0 1

友情鏈接更多精彩內(nèi)容