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

Cam*_*eln 20 javascript

在UPDATE 2/ANSWER中回答下面的内容

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

原始问题

虽然在JavaScript中使用Namepsaces时做的最佳做法的一些研究,我碰到这个定义中的"模型模式"的:http://yuiblog.com/blog/2007/06/12/module-pattern/.

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

它已经关闭了,所以呢?(请参阅:为什么这个函数包含在括号中,后跟括号?它也没有回答我的问题=).

假设以下设置代码..

var MyNamespace = window.MyNamespace || {};
Run Code Online (Sandbox Code Playgroud)

哪个是首选,为什么?

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;
})();
Run Code Online (Sandbox Code Playgroud)

更新:

看起来像jQuery一样,所有酷孩子都在使用"自我执行匿名函数"(SEAF)!但我只是不明白这一点,因为我发现使用.UsingNew方法更清晰,因为你在定义中公开公共函数(而不是在需要单独维护或被迫使用内联对象的返回中)符号).

由于以下几个原因,不需要"那=这个"的论据并不适合我:

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

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

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

或者如果它是私有静态功能......

var PrivateStaticFunct = function(oContext) {
    //...
};
Run Code Online (Sandbox Code Playgroud)

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

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

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

更新2:

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

Per Douglas Crockford(参见:JS我们几乎没有新的Ya)匿名函数永远不应该使用"new"关键字,因为:

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

所以看来问题的关键是:SEAF var obj = new function() {...};比速度更快,开销更少(没有不需要的原型对象).你必须通过遭受什么是事实,你不得不使用对象的文字符号(因此,的而不是;"你的公有成员s之间),或在返回对象,以保持公共对象的单独列表.

SEAF的都是不可取的,当你正打算为对象的构造函数工作的功能instanceof将不会按预期工作(见:创建从JS关闭对象:我应该用"新"的关键字?).

回答:

  • 如果它是一个旨在用作Singleton/Global静态实例的匿名函数,请使用SEAF.
  • 如果您打算将其用作Constructor(可能代表多个对象)或使用.prototype,请使用"标准"函数定义并使用"new"调用,例如:

    function PseudoClass1() {}

    var PseudoClass2 = function() {};

    var myClass1 = new PseudoClass1();

    var myClass2 = new PseudoClass2();

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

Jos*_*eph 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();
    }
};
Run Code Online (Sandbox Code Playgroud)
  • 使用"new"关键字创建对象的实例,该实例使用构造函数建模.忘记使用"新",你最终会命名为一个函数MyNamespace.UsingNew()而不是一个对象.

  • 它是一个构造函数,而不是一个对象的实例(直到你使用new构建它).你需要使用"this"来描述它将成为的对象.它只是向范围添加问题,特别是当你在其中嵌入更多函数时,"this"的值会不时改变(并且在控制台告诉你之前你不会看到它).熟悉self=thisthat=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
    };
}());
Run Code Online (Sandbox Code Playgroud)