JavaScript单例模式和'this'

6

在阅读了很多有关单例模式的文章并进行一些测试后,我发现像这样的单例模式 (http://jsfiddle.net/bhsQC/1/) 并没有什么区别:

var TheObject = function () {
    var instance;

    function init() {
        var that = this;
        var foo = 1;

        function consoleIt() {
            console.log(that, foo);
        }
        return {
            bar: function () {
                consoleIt()
            }
        };
    }
    return {
        getInstance: function () {
            if (!instance) {
                instance = init();
            }
            return instance;
        }
    };
}();
var myObject = TheObject.getInstance();
myObject.bar();

并且像这样的代码 (http://jsfiddle.net/9Qa9H/3/):

var myObject = function () {
    var that = this;
    var foo = 1;

    function consoleIt() {
        console.log(that, foo);
    }
    return {
        bar: function () {
            consoleIt();
        }
    };
}();
myObject.bar();

他们都只需要创建一个对象实例,两者都可以拥有“私有”成员,无论哪个,that指向window对象。只是后者更简单。如果我说错了,请纠正我。
使用标准构造函数如下(http://jsfiddle.net/vnpR7/2/):
var TheObject = function () {
    var that = this;
    var foo = 1;

    function consoleIt() {
        console.log(that, foo);
    }
    return {
        bar: function () {
            consoleIt();
        }
    };
};
var myObject = new TheObject();
myObject.bar();

这种方法在正确使用that的同时,没有单例模式的优势。

我的问题是:这三种方法的总体优缺点是什么?(如果有影响的话,我正在使用Dojo 1.9制作Web应用程序,因此无论哪种方式,该对象都将位于Dojo的require中)。


1
仅出于好奇,为什么有人会在JavaScript中使用单例模式?使用一个对象不是更有意义吗,例如:var obj1 = {}。抱歉离题了。 - Kirill Ivlev
使用单例/模块模式,您可以在IIFE内部拥有私有变量和函数。 OP的单例似乎也应用了延迟加载-仅在第一次调用时实例化。 - Fabrício Matté
我真的不明白为什么你想把“那个”点放到“窗口”上? - Bergi
请查看CMS的这个答案:https://dev59.com/63M_5IYBdhLWcg3wNgKZ#1479341 - hegemon
@hegemon 在我发布之前已经阅读过了,但我仍然不确定。 - Zemljoradnik
显示剩余5条评论
3个回答

3
实际上,两种方法的区别在于单例模式的构建时间。第二种方法会立即创建单例对象,而第一种方法只有在第一次调用时才会创建。根据单例模式需要占用的内存空间,这可能会对你的应用程序产生影响。例如,如果用户没有执行特定操作,则可能根本不需要初始化单例模式,这样就可以避免不必要的开销。此外,如果单例模式的初始化计算量很大,那么能够将其推迟到真正需要该单例模式时就是一个好事情。 编辑:正如Jani所说,最后一种方法并不是单例模式,因此我没有讨论它。

嗯,是的,我错过了显而易见的东西——构建时间。在我的情况下,这并不重要,因为我将其用作命名空间。这就是为什么我包括了第三个选项,因为我仍然不确定是否应该使用单例模式... - Zemljoradnik
好的,我没有看到任何其他显著的区别。至于你是否应该使用单例模式,那当然是另外一个讨论 :) - ghost23

1
我认为前两种方法并没有实际的大区别。
第一种方法使用 `getInstance` 更像是传统 OOP 语言(如 Java)中的单例模式。
第二种方法更像是传统 OOP 语言中的静态类。
显然,这两种方法都有与所有单例模式相同的问题(如果您在 Google 上搜索,会有很多相关材料)。
最后一种方法甚至没有真正使用 `new` - 您从“构造函数”中返回一个对象。显然,这不是一个单例模式,因此,这应该是首选的方法。

我为这个问题做好了被踩的准备,但是除了“那个”问题之外,单例模式还有哪些“问题”?虽然有很多相关的问题,但我就是找不到什么好答案。 - Zemljoradnik
1
这里有一些关于此问题的好答案,可以在SO上找到:https://dev59.com/YXVC5IYBdhLWcg3w9GA9 - Jani Hartikainen

0

我喜欢像这样构建单例:

function FriendHandler(){ 
    if(FriendHandler.prototype.singleton){ 
        return FriendHandler.prototype.singleton; 
    }

    if(!(this instanceOf FriendHandler)){
        return new FriendHandler();
    }

    FriendHandler.prototype.singleton = this;
 ...
    this.selectFriends = function(firstName){
        ...
    };
}

如果你这样做:

new FriendHandler()
or
FriendHandler()

它总是返回相同的实例。

我几个月前写过关于它的文章:http://franciscomsferreira.blogspot.com/2013/01/how-to-write-maintainable-javascript-or.html


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接