为什么这个JavaScript代码(RequireJS和Node.js的模块模式)有效?

gre*_*emo 5 javascript module function node.js requirejs

由于我对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
Run Code Online (Sandbox Code Playgroud)

我能理解的(希望如此):

  • 当脚本未包含在<script>标记中时,将自动执行包装代码的匿名函数
  • 此代码适用于RequireJS和Node.js(if最开始检查); factory函数的结果既可以分配给module.exports(Node.js),也可以用作函数的define参数(RequireJS).

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

Q2:this作为root论点传递的目的是什么?它从未使用过

Ale*_*ich 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);
}
Run Code Online (Sandbox Code Playgroud)

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