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

发布于 2024-10-15 04:11:55 字数 513 浏览 5 评论 0原文

查看一些 JavaScript 库和其他人的代码,我看到了两种常见模式,我不知道使用其中一种是否有区别或优势。这些模式看起来有点像这样:

1.

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

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

    return obj;
})();

2.

(function () {
    // Private vars

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

    window.app = obj;
})();

这些模式是否相同,或者其中一种模式比另一种模式具有优势或用途不同?

提前致谢。

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. The patterns look sort of like this:

1.

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

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

    return obj;
})();

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

无远思近则忧 2024-10-22 04:11:55

第二个假设父作用域中存在一个名为 window 的对象,并在那里分配一个属性。

第一个将其留给调用者进行分配,并且不依赖于定义的窗口(它可能仅位于网络浏览器内部)。

所以,我想说第一个肯定更好(更独立,更少依赖环境)。

The second assumes the existence of an object called window in the parent scope and assigns a property there.

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).

So, I'd say the first one is definitely better (more self-contained, less environment-dependent).

带刺的爱情 2024-10-22 04:11:55

tl;dr:选择一种方法并保持一致


在我看来,第一种方法在可读性方面略有优势。在我的脑海中,当我读到它时,我看到“模块 app 正在被定义”,并且这个闭包内部的所有内容都属于该模块。这对我来说是一个自然的分解,并强加了即将定义的模块的面向对象性质。

我喜欢第一种方法的另一个原因是,更改模块定义的范围更清晰。您定义的每个模块都不需要成为全局范围的一部分。使用第二种方法,如果范围不是通过将父对象传递为 Jared Farrish 通过他的 jQuery 示例进行了说明,如果您决定更改该父对象的名称,那么您将面临破坏代码的风险。此示例说明了这一点:

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

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

每当标识符 namespacesubns 发生更改时,您还必须更新此模块以及遵循此模式并将其自身添加到同一对象的任何其他模块。

总而言之,方法一和方法二(带有依赖注入)都不比另一个“更好”,这只是一个偏好问题。此讨论的唯一好处是您应该选择一种方法并保持一致

tl;dr: pick one method and be consistent.


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. 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. 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.

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.

任谁 2024-10-22 04:11:55

它们都完成相同的事情,即在代码运行时在全局命名空间中创建一个对象。

一个并不比另一个更“硬编码”,因为两者都没有进行任何类型的函数原型设计,在该原型设计中您可以使用 new 关键字创建对象的克隆。在我看来,这只是一个偏好问题。

例如,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.$,

...

但是 Prototype JS 库做了前者:

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)
    }
  })(),

...

我不知道为什么一个比另一个更好,或者他们以不同的方式完成他们的任务(在窗口命名空间)。

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. It's just a matter of preference, in my opinion.

For instance, jquery does something akin to the latter:

(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:

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).

治碍 2024-10-22 04:11:55

在第一个示例中,如果 app 在另一个函数中定义,则 app 将仅在该本地范围内可用,而在第二个示例中 app变量被显式分配给全局范围。

在第二个示例中,如果在函数外部的全局作用域中定义,则仅将 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.

In the second example, the app will only be assigned to the global scope if defined in the global scope outside of functions.

绿萝 2024-10-22 04:11:55

第二种形式有一个轻微的优势,因为你有一个完全独立的功能;例如,您的 JS 文件可以有一个标准的页眉和页脚。

我不完全相信的部分是块内的局部变量。我倾向于更喜欢这个:

(function () {
   // Private vars

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

尽管当您做不止一件事时,例如使用多个方法而不是像本例中的单个对象构建一个对象,这会有点崩溃。

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.

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文