简体   繁体   English

这两种JavaScript模式之间有什么区别吗?

[英]Is there any difference between this two JavaScript patterns?

Looking at some JavaScript libraries and other people's code I've seen two common patterns, I don't know if there is a difference or advantage in using one of them. 看一些JavaScript库和其他人的代码,我看到了两种常见的模式,我不知道使用其中一种是否存在差异或优势。 The patterns look sort of like this: 模式看起来像这样:

1. 1。

var app = (function () {
    // Private vars

    // Module
    var obj = {
        prop: "",
        method: function () {}
    };

    return obj;
})();

2. 2。

(function () {
    // Private vars

    // Module
    var obj = {
        prop: "",
        method: function () {}
    };

    window.app = obj;
})();

Are this patterns the same or do one of them has an advantage or different use than the other? 这些模式是相同的还是其中一个比另一个具有优势或用途?

Thanks in advance. 提前致谢。

The second assumes the existence of an object called window in the parent scope and assigns a property there. 第二个假设在父作用域中存在一个名为window的对象,并在那里分配一个属性。

The first one leaves it up to the caller to make the assignment, and does not depend on a window being defined (which it probably is only inside of a web browser). 第一个将它留给调用者进行赋值,并且不依赖于定义的window (它可能只在Web浏览器中)。

So, I'd say the first one is definitely better (more self-contained, less environment-dependent). 所以,我会说第一个肯定更好(更独立,更少依赖环境)。

tl;dr: pick one method and be consistent . tl; dr: 选择一种方法并保持一致


In my opinion, the first method has a slight advantage for readability. 在我看来,第一种方法在可读性方面略有优势。 In my head, when I read it, I see that, "module app is being defined," and that everything inside of this closure belongs to that module. 在我的脑海中,当我阅读它时,我看到,“正在定义模块app ”,并且此闭包内的所有内容都属于该模块。 This is a natural decomposition for me and imposes the object oriented nature of the module about to be defined. 这对我来说是一种自然的分解,并强加了即将定义的模块的面向对象特性。

Another reason I favor the first method is that it is cleaner to change the scope into which a module is defined. 我赞成第一种方法的另一个原因是更改模块定义的范围更清晰。 Every module you define wont need to be part of the global scope. 您定义的每个模块都不需要成为全局范围的一部分。 Using the second method, if the scope isn't injected by passing in a parent object as Jared Farrish illustrates with his jQuery example, then you run the risk of breaking your code if you decide to change the name of that parent object. 使用第二种方法,如果未通过传递父对象注入作用域,正如Jared Farrish用他的jQuery示例所示,那么如果您决定更改该父对象的名称,则存在破坏代码的风险。 This example illustrates the point: 这个例子说明了这一点:

var namespace = {
  subns: { ... }
};

(function() {
  var module = { ... };
  namespace.subns.someModule = module;
}());

Anytime the identifiers namespace or subns change, you also have to update this module and any other module that follows this pattern and adds itself to the same object. 无论何时标识符namespace或子subns发生更改,您还必须更新此模块以及遵循此模式的任何其他模块,并将其自身添加到同一对象。

All in all, neither method one nor method two (with dependency inject) is "better" than the other, it is simply a matter of preference. 总而言之,方法一和方法二(依赖注入)都不比另一方“更好”,这只是一个偏好问题。 The only benefit that can come from this discussion is that you should pick one method and be consistent . 这个讨论可以带来的唯一好处是你应该选择一种方法并保持一致

They are both accomplishing the same thing, to create an object in the global namespace at the time the code is run. 他们都在完成同样的事情,在运行代码时在全局命名空间中创建一个对象。

One isn't more "hardcoded" than the other, since neither is doing any kind of function prototyping in which you could create clones of the object with the new keyword. 一个并不比另一个更“硬编码”,因为它们都没有进行任何类型的函数原型设计,您可以使用new关键字创建对象的克隆。 It's just a matter of preference, in my opinion. 在我看来,这只是一个偏好问题。

For instance, jquery does something akin to the latter: 例如,jquery做了类似于后者的事情:

(function( window, undefined ) {

// Use the correct document accordingly with window argument (sandbox)
var document = window.document;
var jQuery = (function() {

// Define a local copy of jQuery
var jQuery = function( selector, context ) {
        // The jQuery object is actually just the init constructor 'enhanced'
        return new jQuery.fn.init( selector, context, rootjQuery );
    },

    // Map over jQuery in case of overwrite
    _jQuery = window.jQuery,

    // Map over the $ in case of overwrite
    _$ = window.$,

...

But Prototype JS Library does the former: 但是Prototype JS Library做了前者:

var Prototype = {
  Version: '1.6.1',

  Browser: (function(){
    var ua = navigator.userAgent;
    var isOpera = Object.prototype.toString.call(window.opera) == '[object Opera]';
    return {
      IE:             !!window.attachEvent && !isOpera,
      Opera:          isOpera,
      WebKit:         ua.indexOf('AppleWebKit/') > -1,
      Gecko:          ua.indexOf('Gecko') > -1 && ua.indexOf('KHTML') === -1,
      MobileSafari:   /Apple.*Mobile.*Safari/.test(ua)
    }
  })(),

...

I don't know of any reason why one is better than the other, or that they accomplish their task differently (to create the app object in the window namespace). 我不知道为什么一个比另一个更好,或者他们以不同方式完成任务(在窗口命名空间中创建app对象)。

In the first example, if app defined within another function, app will only be available in that local scope, whereas in the second example the app variable is explicitly assigned to the global scope. 在第一个示例中,如果app在另一个函数中定义, app将仅在该局部范围内可用,而在第二个示例中, app变量显式分配给全局范围。

In the second example, the app will only be assigned to the global scope if defined in the global scope outside of functions. 在第二个示例中,如果在函数外部的全局范围中定义,则仅将app分配给全局范围。

The second form has a slight advantage in that you have a completely self contained function; 第二种形式有一个小优势,因为你有一个完全独立的功能; for example you could then have a standard header and footer for your JS files. 例如,您可以为JS文件提供标准页眉和页脚。

The part I'm not completely sold on is the local variable inside the block. 我没有完全售出的部分是块内的局部变量。 I tend to prefer this: 我倾向于这样:

(function () {
   // Private vars

   // Module
   window.app = {
       prop: "",
       method: function () {}
   };
})();

although that breaks down a bit when you're doing more than one thing, such as building up an object with multiple methods rather than a single object as in this example. 虽然当你做了不止一件事情时,这会有所破坏,例如使用多个方法而不是像本例中的单个对象构建对象。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM