为什么Backbone.js代码前面有(function($){.



这是Backbone.js代码的一个示例(取自本教程):

// **This example illustrates the binding of DOM events to View methods.**
//
// _Working example: [2.html](../2.html)._  
// _[Go to Example 3](3.html)_
//
(function($){
  var ListView = Backbone.View.extend({
    el: $('body'), // el attaches to existing element
    // `events`: Where DOM events are bound to View methods. Backbone doesn't have a separate controller to handle such bindings; it all happens in a View.
    events: {
      'click button#add': 'addItem'
    },
    initialize: function(){
      _.bindAll(this, 'render', 'addItem'); // every function that uses 'this' as the current object should be in here
      this.counter = 0; // total number of items added thus far
      this.render();
    },
    // `render()` now introduces a button to add a new list item.
    render: function(){
      $(this.el).append("<button id='add'>Add list item</button>");
      $(this.el).append("<ul></ul>");
    },
    // `addItem()`: Custom function called via `click` event above.
    addItem: function(){
      this.counter++;
      $('ul', this.el).append("<li>hello world"+this.counter+"</li>");
    }
  });
  var listView = new ListView();      
})(jQuery);

我不明白为什么它前面必须有一个(function($){...

有人能向我解释一下吗?

这是编写jQuery插件时的常见做法。

原因是您希望避免与其他库发生冲突,这些库也可能在全局范围中使用$符号。通过将代码包装在接受一个参数(名为$)的函数调用中,并将jQuery对象传递到该函数中,可以确保避免冲突。

function($) { // declare an anonymous function that takes an argument $
    // conflict safe code =)
}(jQuery); // pass the argument jQuery to the anonymous function

正如nielsbot所指出的,如果你给函数起一个名字:,那么上面的代码可能会更容易理解

var executeSafely = function($) {
    // conflict safe code =)
}
executeSafely(jQuery);

我知道这是事后的方式,但MikeG刚刚在这篇文章的评论中指出,在其他地方使用javascript代码并不一定是坏事。我想我应该扩展一下原因:

范围界定案例

假设您的网站上有两个独立的javascript模块。假设您已经在两个js文件module-one.jsmodule-two.js中为它们编写了代码。通常,一个页面上只有一个模块,因此在编写其中一个模块时,您不在乎另一个模块会发生什么(甚至可能有不同的开发人员独立于另一个开发不同的模块)。

然后,您决定在起始页上同时显示这两个内容会很好,因此您在起始页html的头部包含以下内容:

<script type="text/javascript" src="module-one.js" />
<script type="text/javascript" src="module-two.js" />

[提示:末日音乐!]一切都崩溃了!到底发生了什么事?

您可以查看模块的代码,并看到以下内容:

module one.js:

var state = 0;
function init() {
    ...
}
etc...

模块二.js:

var state = 2;
function init() {
    ...
}
etc ...

这是怎么回事

好吧,页面按顺序加载两个脚本——加载了第一个模块-one.js,第一个模块一切正常;然后,加载module-two.js,覆盖第一个模块中定义的一些变量这是因为在JavaScript中的全局范围中定义变量,它被隐式地解释为在window对象上定义它。因此,如果两个脚本文件相继运行,例如,首先设置window.state = 0,然后设置window.state = 2。正如您所看到的,这些模块并不是真正独立的。例如,当在加载两个脚本后调用init()(或者实际上是window.init())时,只启动第二个模块——第一个init()函数被覆盖(因为window只能有一个名为init的属性),并且不再存在。

救援范围

为了避免这个问题,您应该将模块封装在函数调用中,就像上面使用jQuery插件一样。然而,这些函数不需要接受任何参数:

模块one.js

(function() {
    // code for module one here
})();

模块二.js

(function() {
    // code for module two here
})();

现在,由于这两个模块是在单独的函数中定义的,所以所有变量的作用域都只在这些函数中。如果您不确定如何使用JavaScript代码,那么将其封装在这样的函数调用中是避免冲突的好做法。由于如果你不一直遵循好的做法,很难记住它们,所以一直遵循这个做法真的不会伤害任何人=)

这是为了保证$在定义的函数中被分配给jQuery对象。他们基本上是这样做的:

var theFunction = function($){...code...};
theFunction(jQuery);

你看到了吗?

最新更新