用使用'new'关键字的Javascript函数表达式视为“静态”是否正确?

29

我只是想更深入地了解JavaScript。

我创建了一个名为gameData的“类”,我只需要一个实例,不需要构造函数或实例化。

因此我这样创建它...

var gameData = new function () {

    //May need this later 
    this.init = function () { 
    };

    this.storageAvailable = function () {
        if (typeof (Storage) !== "undefined") {
            return true;
        }
        else {
            return false;
        }
    };
}

意识到 'new' 关键字不能实例化类,并使其像 C# 中的静态类一样可用。

我想得对吗?就像静态一样?


3
如果你只需要一个对象的单个实例,为什么还需要使用构造函数呢? - RobG
我不确定我理解你的问题。我这样创建它,而不是使用基本对象文字,这样我就可以拥有私有和公共属性和方法。 - Todd Vance
相关链接:https://dev59.com/cWQn5IYBdhLWcg3wNk7t#17008693 - Benjamin Gruenbaum
请参见JavaScript中小写字母"f"的new function()(https://dev59.com/ZHE95IYBdhLWcg3wheRR)。 - Bergi
3个回答

30

不,它不是静态的,因为它仍然有一个指向你的“匿名”函数的 constructor 属性。在你的例子中,你可以使用:

var gameData2 = new (gameData.constructor)();

为了重新实例化第二个对象,所以这个“类”(实际上是实例)并不是真正的“静态”。你基本上是泄露了构造函数,可能也会泄露绑定在它上面的数据。另外,会创建一个无用的原型对象(gameData.constructor.prototype),并将其插入到gameData的原型链中,而这并不是您想要的。

相反,你可以使用:

  • 一个单一、简单的对象字面量(例如Daff的答案)。这意味着没有构造函数,也没有闭包范围内的私有变量(您根本没有使用),也没有(自定义)原型。
  • (揭示)模块模式(例如jAndy的答案)。在那里,您将拥有一个IIFE来创建闭包范围内的变量,并可以返回任何类型的对象。
  • 一个实际的构造函数("class"),可以在稍后(需要时)实例化,并始终产生相同的单例对象。

这就是单例模式的样子:

function GameData() {
    if (this.constructor.singleton)
        return this.constructor.singleton;
    else
        this.constructor.singleton = this;

    // init:
    // * private vars
    // * public properties
    // ...
}
GameData.prototype.storageAvailable = function () {
    if (typeof (Storage) !== "undefined") {
        return true;
    }
    else {
        return false;
    }
};

var gameData = new GameData();
var gameData2 = new GameData();
gameData === gameData2 === GameData.singleton; // true

然而,原型并不是很有用,因为你只有一个GameData的实例。只有通过继承才会变得更加有趣。


16

ECMAscript中没有Class,只有Object

当使用new调用函数时,我们将其称为构造函数。一旦完成,该函数会自动返回一个新对象。使用this(引用新创建的对象)在其中存储的任何数据都将作为该对象的属性返回。此外,new会将一个名为constructor的属性设置为正好是这个函数。

在你的情况下,你甚至不需要真正使用new,你可以轻松地将代码重新编写如下:

var gameData = (function () {
    var public = { },
        private = { }; // any private data can get stored here

    //May need this later 
    public.init = function () { 
    };

    public.storageAvailable = function () {
        if (typeof (Storage) !== "undefined") {
            return true;
        }
        else {
            return false;
        }
    };

    return public;
}());

这被称为 工厂模式单例模式模块模式,可能还有其他名称。


1
你应该称其为“自调用匿名工厂”。 - Bergi
2
@toddv:一个非常好的建议和推荐是阅读Douglas Crockford的《JavaScript: The good parts》,以了解ECMAscript继承、对象+原型。 - jAndy
这不是单例模式。另外,ES -> ES5。 - Benjamin Gruenbaum
3
“ECMAscript中没有类”。 实际上,随着ES6的出现,现在有了类。 - Stijn de Witt
2
这不仅仅是相同事物的更清晰的语法吗?-“类实际上是函数” https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Classes - Tom
显示剩余2条评论

5
我认为你要找的只是一个简单的JavaScript对象:
var gameData = {
    //May need this later 
    init : function () { 
    },

    storageAvailable : function () {
        if (typeof (Storage) !== "undefined") {
            return true;
        }
        else {
            return false;
        }
    }
}

如果想要使用私有变量,可以创建一个揭示模块模式样式的包装器。这基本上就是jAndy建议的内容:
var gameData = (function() {
    var private = 'private variable';

    return {
        //May need this later 
        init : function () { 
        },

        storageAvailable : function () {
            if (typeof (Storage) !== "undefined") {
                return true;
            } else {
                return false;
            }
        }
    }
})();

1
我没有选择这条路,是因为我想要有公共和私有方法以及构造函数,而使用对象字面量无法实现这一点,对吗? - Todd Vance
2
我更新了有关私有变量的答案。但是我不明白为什么你需要一个静态类的构造函数? - Daff

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