单例通过对象文字与模块模式,代码组织的优点和缺点

时间:2014-08-04 15:15:13

标签: javascript

您更喜欢哪一个,哪个是专业人士?一个人在另一个人身上? 我个人认为单身人士难以阅读和维护,很多情境变化( this ),总是以var self = this(或某些代理人,如$.proxy)缓存正确的上下文结束我将永远有一个全局变量(单例),而在第二种方法中,如果模块不需要公开任何API,我可以避免创建全局变量。

简单示例:
(用户点击"添加到购物车",一些ajax被触发,成功html(通知)被创建)
HTML

<div class="cart">
    <a href="#" data-product-id="200"> Add to cart </a>
</div>

模块模式
根据定义,不是真正的模块模式,因为我没有从中返回任何内容,单击处理程序可以通过闭包访问外部作用域。

;(function(window, $, undefined) {

    function constructHtml(data) {...}

    function addToCart(product_id, quantity) {
        ...

        $.ajax({
            ...
            success: function(data) { constructHtml(data); }
        });
    }


    $(function() {
        var $addBtn = $('div.cart a');
        var productId = $addBtn.data('product-id');

        $addBtn.click(function(e) {
            e.preventDefault();
            addToCart(productId);
        });
    });

})(this, jQuery);

Singleton - Object literal(相同示例)

var Cart = {
    settings: {
        $addBtn: $('div.cart a'),
        productId: $('div.cart a').data('product-id') 
    },
    init: function() {
        this.bindUiActions();
    },
    bindUiActions: function() {
        var self = this;

        this.settings.$addBtn.click(function(e) {
            e.preventDefault();

            self.addToCart(self.settings.productId);
        });
    },
    addToCart: function(product_id, quantity) {
        ...
        var self = this;

        $.ajax({
            ...
            success: function(data) {
                self.constructHtml(data);
            }
        });
    },
    constructHtml: function(data) {...}
};

Cart.init();

2 个答案:

答案 0 :(得分:1)

虽然Singleton vs. Module Pattern可以是一个合法的问题,但是你给出的例子,这个问题应该改写为Singleton vs IIFE,因为它不是模块模式本身,而是IIFE,模块模式被包裹在内,这样可以防止Cart单例出现。即便如此,这也不是一个问题 - IIFE和Singleton可以一起使用。 IIFE的目的只是为了使东西远离全球范围。

所以......,您可以将您的单身代码打包成IIFE,如下所示

;(function(){
  var Cart = {
    settings: {
      // Your code ...
  };

  Cart.init();
})();

在这种情况下,您将代码编写为Singleton,但将其包装在IIFE中,并且不使用全局范围。 IIFE完全独立于您选择编写和组织代码的方式。对于Singleton vs. Module Pattern问题,您需要一个不同的示例。

答案 1 :(得分:0)

IIFE(立即调用函数表达式):

(function() {
    console.log('run this in your browser console')
})()

模块模式:

var module = (function () {
    var privateScopeVar = 1 // scope of the IIF  

    // the 'this' context in this scope is the global object (e.g. window)

    // returns literal object who's method's scopes are lexically bound 
    // to the IIF scope
    return {
      publicMethod: () => privateScopeVar // publicMethod scope can access IIF scope 
    }
})()

在EcmaScrip5中多次包含/导入时无法覆盖的Singleton Literal + Singleton Literal:

var singleInstance = { firstName: 'Greg' }
var singleInstance = singleInstance || { firstName: 'Greg' }

在EcmaScrip6中无法多次覆盖或初始化的Singleton Literal:

const singleInstance = { 
    firstName: 'Greg', 
    called: false, 
    init: () => { 
        if (!this.called) {
            console.log('only once')
            this.called = true
        }
    } 
}

// of course singleInstance.called = false; singleInstance.init() is always possible

IIF内的单身人士(提供私人状态)

const singleton = (function () {
    // IIF private scope ensures there is a single instance ever
    var storedInstance

    // Also some private state for the singleton instance as well
    const firstName = 'Greg'


    // literal object that holds constructor function
    const Singleton = {
        getInstance: () => {
            if (!storedInstance) {
                storedInstance= {
                    getName: () => firstName
                }
            }
            return storedInstance
        }
    }

    return Singleton
})()