5

由于我对 RequireJS 和 Node.js(加上一般的 JavaScript)的了解有限,我通常会看看一些知名 JavaScript 库的源代码。每次我看到这样的东西:

( // 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>标签中时,包装代码的匿名函数会自动执行
  • 此代码适用于 RequireJS 和 Node.js(if一开始就检查);函数的结果factory要么分配给module.exports(Node.js),要么用作函数的参数define(RequireJS)。

Q1:这段代码在没有 RequireJS 和 Node.js 的情况下如何工作?if并且else if检查将失败,factory函数永远不会执行并且脚本不会返回任何内容。

Q2this :作为root参数传递的目的是什么?它从未使用过

4

2 回答 2

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页面上的其他标签定义。希望这能回答你的第二个问题。

于 2013-02-08T22:23:58.567 回答
2

Q1:如果 theif和 the都else if失败了,唯一可以假设的是underscoreand是从标签Backbone加载的。<script>前段时间,我向Backbone.localStorage 插件添加了一个提交,它做了同样的假设。

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

于 2013-02-08T21:15:16.020 回答