2013-02-08 55 views
5

由于我对RequireJS和Node.js的理解有限(通常加上JavaScript),我通常会看一些知名JavaScript库的来源。每次看到这样的事情:为什么这个JavaScript代码(RequireJS和Node.js的模块模式)工作?

(// Wrapping 
    function (root, factory) { 
     if (typeof exports === 'object') { // Node.js 

      var underscore = require('underscore'); 
      var backbone = require('backbone'); 

      module.exports = factory(underscore, backbone); 

     } else if (typeof define === 'function' && define.amd) { // Require.JS 

      define(['underscore', 'backbone'], factory); 

     } 
    }(this, function (_, Backbone) { // Factory function, the implementation 
     "option strict"; 

     function Foo() {} 

     return Foo; // Export the constructor 
    }) 
); // Wrapping 

我能理解(希望):

  • 当脚本在<script>标签uncluded自动执行换行代码中的匿名函数
  • 此代码与RequireJS和Node.js(最初的if检查)一起使用;函数factory的结果被分配给module.exports(Node.js)或用作define函数(RequireJS)的参数。

Q1:此代码是如何工作没有RequireJS和Node.js的? ifelse if检查将失败,factory函数从不执行并且脚本返回nothig。

Q2:通过this作为root参数的目的是什么?这是从来没有使用

+1

你确定它没有RequireJS或Node.js吗?我对JavaScript的理解有限(这可能是错误的)[JSFiddle](http://jsfiddle.net/aM3ZT/)让我觉得你不能访问Foo() – 2013-02-08 21:17:01

+0

@nekman啊我看到它假定至少有Backbone可用。这是聪明的 – 2013-02-08 21:18:01

+0

@JasonSperske不能确定100%,但看看nekman的答案...... – gremo 2013-02-08 21:22:00

回答

5

其实我认为在你的问题中剪去的代码不适用于浏览器全局变量。在此剪切中使用的模式称为UMD - 通用模块定义。事实上,有这种模式的很多变化,你可以浏览更多的例子在https://github.com/umdjs/umd

至于问题:

Q1 这个片段将不会在浏览器中没有RequireJS或任何其他AMD装载机工作,为显而易见的原因 - 只有两次检查 - 对于NodeJS和定义函数,所以不使用AMD库时不会调用工厂函数。

为了使所谓的添加另一条件浏览器全局

if (typeof exports === 'object') { // Node.js 
    var underscore = require('underscore'); 
    var backbone = require('backbone'); 
    module.exports = factory(underscore, backbone); 

} else if (typeof define === 'function' && define.amd) { // Require.JS 
    define(['underscore', 'backbone'], factory); 
} else { 
    // Browser globals 
    factory(root._, root.Backbone); 
} 

请注意,我们使用传递到包装函数根对象和nekman指出它将被设置为在浏览器环境window出厂功能,所以我们只是将在该窗口中定义的全局对象传递给工厂,这些对象通常由页面上的其他script标签定义。希望这回答你的第二个问题。

+0

+1,感谢UMD链接!正如我所说我正在学习JavaScript,而我不明白的是如何在不使用Node.js或Require.JS时访问'Foo'构造函数。唯一的方法是编写'root.Foo = factory(root._,root.Backbone)',对吧? – gremo 2013-02-08 22:35:45

+0

其实我在这里找到了我评论的答案:https://github.com/umdjs/umd/blob/master/returnExports.js – gremo 2013-02-08 22:39:56

+0

是的,这是做到这一点的方法,你只需返回你的对象(' Foo'),如果我们在浏览器中,我们应该将它添加到'root'(这是窗口),以便其他模块可以看到它。 – 2013-02-08 22:41:18

2

Q1:如果同时ifelse if失败,承担的唯一的事情就是underscoreBackbone<script>标签加载。一段时间前,我做了added a commitBackbone.localStorage plugin做了相同的假设。

Q2:this将指向“全局对象”(window在浏览器环境和global在Node.js的环境)。在你的情况下,它不会被使用,也不需要传入。单独使用factory就足够了。

+1

对于** Q1 **:我无法理解当if和else if失败时正在执行的行即浏览器)。你能解释一下吗?我如何访问'Foo()'? – gremo 2013-02-08 21:20:42

+1

是的,这是正确启动!如果两者都失败了,那么应该有一个:else {factory(_,Backbone); }'访问工厂和'Foo'。 – nekman 2013-02-08 21:28:32

+0

即使有'return factory(_,Backbone)'我也搞不明白,在包含'