AMD兼容的JavaScript-定义然后返回与仅返回之间的任何区别



我想知道以下之间是否有任何区别

define(
    function () {
        var Dog = {
             Bark: function () { alert('Woof! Woof! Woof!'); }
        };
    return Dog;
});

define(
    function () {
        return {
             Bark: function () { alert('Woof! Woof! Woof!'); }
        };
});

define(
    function () {
        function Dog()  {
             this.Bark = function () { alert('Woof! Woof! Woof!'); };
        };
    return Dog;
});

就外观而言,我更喜欢第一个,但我担心它与第二个和第三个不同,因为它在返回之前会经过评估。。。我意识到这是一个愚蠢的语句,因为显然所有的函数声明都需要在某个时候进行评估,但我不知道JavaScript在后台是如何工作的,我希望能澄清一下。

第一个和第二个几乎相同。真正的区别可以在第三个选项中注意到。在这种情况下,您将返回一个函数,该函数可能会用new运算符调用。然而,第三种选择有一些缺点,使其成为最糟糕的选择:

所有Dog函数的Fisrt将创建一个新对象,在内存中分配一个新的Bark功能。因此,就内存效率而言,这个选项显然比其他两个最差,因为其他两个选项只创建了一个分配给单个Bark函数的对象。回到第三种情况,你可以通过以下操作来改进它:

define(
    function () {
        function Dog()  {
        };
        Dog.prototype.Bark = function () { alert('Woof! Woof! Woof!'); };
    return Dog;
});

通过这样做,您可以确保只有一个Bark函数的实例,该实例将由使用Dog功能创建的所有对象共享。

我注意到的另一个缺陷是,您没有确保Dog函数将创建一个对象。我的意思是,如果在没有运算符的情况下调用它,会发生什么?。这可能是像这样的非常讨厌的错误的原因:

var tommy = Dog();
tommy.Bark(); //Bark is undefined because tommy is equal to Dog's return value

所以要处理这个问题,你可以做:

define(
    function () {
        function Dog()  {
            if(!(this instanceof Dog)){
                return new Dog();
            }
        };
        Dog.prototype.Bark = function () { alert('Woof! Woof! Woof!'); };
    return Dog;
});

有了这个改进的第三个选项,选择取决于您试图解决的问题。您需要该对象的多个实例吗?如果是这种情况,那么您应该使用改进的第三个选项,否则您可以使用第一个或第二个选项。

第一个和第二个示例实际上是相同的,在第一个示例中,您只需通过使用临时变量命名对象来向读取器发出返回对象"类型"的信号。需要注意的一点是,这个对象在所有需要这个模块作为依赖项的模块中都是共享的,因此是一种单例。

第三个则大不相同。如果Dog是该模块的别名,并且需要该模块作为依赖项,则返回的函数将用于根据new Dog()创建新对象(或多个对象)。此函数是共享的,但不包含Bark或其他方法,它的实例包含,但这些不共享。

你可以把第三个也写成

define(function () {
    return function Dog()  {
         this.Bark = function () { alert('Woof! Woof! Woof!'); };
    };
});

其中函数的Dog名称甚至是可选的(但通常建议用于可读性/调试)。

最新更新