死亡竞赛:自我执行匿名功能-vs-“新功能”

时间:2012-03-20 06:41:41

标签: javascript

在UPDATE 2 / ANSWER

中回答下面的内容

感谢Joseph帮助我找到答案(即使我不喜欢它)。

原始问题

在使用JavaScript中的Namepsaces进行一些关于最佳实践的研究时,我偶然发现了"模式模式":http://yuiblog.com/blog/2007/06/12/module-pattern/的这个定义。

自从我在YUI2年前看到它以来,我一直在使用这种模式,本文对这个概念进行了很好的概述。但它没有触及的是为什么"自我执行匿名函数"用来代替"新功能"。这在评论中被提出,但作者没有很好地描述。由于这篇文章已有4年多的历史了(我在网上其他地方找不到答案),我以为我会把它带到这里。

它已经关闭了,所以? (参见:Why is this function wrapped in parentheses, followed by parentheses?,它也没有回答我的问题=)。

假设以下设置代码..

var MyNamespace = window.MyNamespace || {};

哪个是首选,为什么?

MyNamespace.UsingNew = new function() {
    var fnPrivate = function() {
        return "secrets1";
    };

    this.property = "value1";
    this.method = function() {
        return "property = " + this.property + ' ' + fnPrivate();
    }
};

MyNamespace.UsingSelfEx = (function() { //# <- Added "pre-parens" suggested by chuckj
    var fnPrivate = function() {
        return "secrets2";
    };
    var fnReturn = {};

    fnReturn.property = "value2";
    fnReturn.method = function() {
        return "property = " + this.property + ' ' + fnPrivate();
    }

    return fnReturn;
})();

更新

似乎像jQuery一样,所有酷孩子都在使用&#34;自我执行匿名函数&#34; (SEAF)!但我只是没有得到这个,因为我发现使用.UsingNew方法更清洁,因为你在定义中暴露公共函数(而不是在需要单独维护或被迫使用内联对象表示法。)

不需要的论据&#34;那=&#34;由于种种原因,我不能为我喝水:

  • 为了避免&#34; var that = this&#34;你最终要么做一个&#34; var obj&#34;加上一个return语句(必须maint。对public是什么的单独定义)或被强制使用内联对象表示法(return {1,2,3})作为你的公共属性/方法。
  • 您总是可以创建一个私有变量&#34; var that = this&#34;在类/命名空间的顶部并使用&#34;那&#34;贯穿。

现在......我想我的开发风格可能会使.UsingNew模式更容易管理。我的私人&#34;功能几乎总是&#34;静态&#34;在本质上,所以我需要传递上下文(取代&#34;这个&#34;)的需要。我也养成了使用&#34;缩写&#34;的习惯。命名空间,所以当我确实需要访问&#34;这个&#34;我只是通过&#34;缩写&#34;来引用完整的对象。命名空间而不是通过它的完整路径。 E.G:

var PrivateFunct = function() {
    var rThis = Cn._.val; //# The abbreviated form of Cn.Renderer.Form.Validation
    //...
};

或者它是否是私人静态功能...

var PrivateStaticFunct = function(oContext) {
    //...
};

除了上面给出的原因之外,我个人发现.UsingNew方法在源代码中更具可读性。我有一个非常广泛的代码库,在这里使用.UsingNew模式:http://code.google.com/p/cn-namespace/source/browse/Cn.Web/js/Cn/ Validation functionality可能最容易让你快速阅读。我也使用了一些SEAF函数(参见ErrorMessages.js.aspx),但只有在它们有意义的时候。

我无法想象必须维护单独的返回以暴露底部的公共接口!呸!

现在,不要误解我的意思,在很多地方,SEAF对于强制关闭非常有用,但我个人认为它在对象中过度使用。

更新2

经过进一步反思(并且由于在他的回答下与约瑟夫进行了长时间的讨论),似乎有一些规则可以适用于这个死亡事件:

Per Douglas Crockford(参见:JS we hardly new Ya匿名函数不应该使用&#34; new&#34;关键字因为:

  • 使用对象文字更快。
  • 通过使用new来调用函数,该对象保持一个毫无价值的原型对象。这浪费了记忆,没有抵消优势。如果我们不使用new,我们不会将浪费的原型对象保留在链中。 (注意:原型调用在构造函数定义之后,并且作为SEAF或&#34;新的&#34;匿名函数即将被触发,不能使用原型)
  • 使用对象文字所需的代码较少。 (虽然如此,我不同意,因为我讨厌对象字面符号,我更喜欢使用;而不是那样,因为它更具可读性)
  • 将new直接放在函数前面永远不是一个好主意。例如,新函数在构造新对象时没有任何优势。

所以看来问题的关键是:由于速度和较少的开销(没有不需要的原型对象),SEAF优于var obj = new function() {...};。您必须经历的是,您被迫使用对象文字符号(因此,而不是;在您的公共成员之间)或维护一个单独的公共对象列表。返回对象。

如果您打算将函数用作对象构造函数,则不建议使用SEAF,因为instanceof将无法按预期工作(请参阅:creating objects from JS closure: should i use the “new” keyword?)。

解答:

  • 如果它是一个旨在充当Singleton / Global Static Instance的匿名函数,请使用SEAF。
  • 如果您打算将其用作Constructor(可能代表多个对象)或使用.prototype,请使用&#34;标准&#34;函数定义并使用&#34; new&#34 ;,例如:

    调用

    function PseudoClass1() {}

    var PseudoClass2 = function() {};

    var myClass1 = new PseudoClass1();

    var myClass2 = new PseudoClass2();

我不得不说,我对这个答案不满意;)我发现.UsingNew模式在代码库中更具可读性,但由于未使用的原型引用是事实,它比SEAF更慢并且使用更多内存实例化并留在对象链中。

3 个答案:

答案 0 :(得分:8)

首先,这种模式:

MyNamespace.UsingNew = new function() {
    var fnPrivate = function() {

        //what's this in here?

        return "secrets1";
    };

    this.property = "value1";
    this.method = function() {

        //what's this in here?

        return "property = " + this.property + ' ' + fnPrivate();
    }
};
  • 使用“new”关键字创建对象的实例,该实例使用构造函数建模。忘记使用“新”,你最终会命名为一个函数MyNamespace.UsingNew()而不是一个对象。

  • 它是一个构造函数,而不是一个对象的实例(直到你用new构建它)。你需要使用“this”来描述它将成为的对象。它只是在范围中添加问题,特别是当你在其中嵌入更多函数时,“this”的值会不时变化(并且在控制台告诉你之前你不会看到它)。熟悉self=thisthat=this以保存“this”的值?使用这种模式时几乎可以看到它

另一方面,下一个模式对我来说有点好(因为我):

  • 您不需要使用“new”,因为它返回一个对象。

  • 不使用“this”,因为它已经返回一个对象。你甚至不需要“这个”。

另外,我更喜欢用这种方式构建其他模式:

ns.myobj = (function(){

    //private
    var _privateProp = '';
    var _privateMeth = function(){};

    //public
    var publicProp = '';
    var publicMeth = function(){};

    //expose public
    return {
        prop:publicProp,
        meth:publicMeth
    };
}());

答案 1 :(得分:2)

两者几乎相同,应具有相对相同的性能特征。这只是一种风格问题。我个人赞成第二个,但它写得有点时髦。我会写的,

MyNamespace.UsingSelfEx = (function () {
    function fnPrivate() {
        return "secrets2";
    }
    return {
        property: "value2";
        method: function () { 
            return "property = " + this.property + " " + fnPrivate();
        }
    }
})();

你真的不需要围绕这个功能的parens,但是自动执行功能通常会有它们,并且让读者在开始时知道这是一个自我执行的功能。

答案 2 :(得分:0)

我已经看过这个,我喜欢它

var MyThing = (function(){

    function MyThing(args){
    }

    MyThing.prototype = {
        prototypeMethod: function() {}
    };

    return MyThing;
})();

你也可以这样做

MyThing.create = function(args){
    return new MyThing(args);
}

通常它包含在另一个自调用函数中。 为了避免命名冲突。

(function({

})(window);

window对象作为参数传递, 将其分配到较高的范围。

window.MyThing = MyThing;

在这个例子中,您可以使用静态变量,私有等。