JavaScript模块、闭包和作用域

JavaScript Modules, Closures and Scope

本文关键字:作用域 闭包 模块 JavaScript      更新时间:2023-09-26

我使用以下闭包模式来模块化我的代码:

(function(root) {
  // MODULE CODE HERE
  if (typeof module !== 'undefined' && module.exports) { // CommonJS 
    /* var dependencies = require(...) */
    module.exports = myModule;
  } else if (typeof define !== 'undefined' && define.amd) { // AMD
    /* var dependencies...; */
    define([/* dependencies */], function(/* dependencies */) {
      /* Assign closure level vars to respective arguments */
      return myModule;
    });
  } else {
    // Dependencies??
    root.myModule = myModule;
  }
})(this);

即,我们使用特征检测来支持CommonJS模块(例如node.js(、AMD或基本的全局命名空间实例化。

这在node.js中运行良好我还没有测试AMD模式,因为我还在读它(见编辑2:AMD表现出完全相同的效果(;但如果模块有任何依赖关系,则在浏览器中失败。也就是说,如果myModule引用了在不同模块中定义的东西:例如,如果我有分别具有模块定义的super.jschild.js,如上所述,其中super.js创建了一个名为root.super(浏览器中的root === window(的函数,如果child.js尝试执行super(),我将获得类似super is not a function的东西。

这是怎么回事?

为了修复它,我更改了super.jschild.js<script>元素中加载的顺序:运气不好。然后,我尝试在文档准备好时使用jQuery:强制加载child.js

$(document).ready(function() {
  $.getScript('child.js', function() {
    // Do stuff with child, which calls super
  });
});

同样的问题。然而,在这两种情况下,如果我进入控制台,super是可用的,并按照我的期望进行定义。

为什么child.js中的super可能来自不同的(即,不是全局的(范围?


我应该补充一点,如果我删除CommonJS导出中的依赖项注入位,它在node.js中会失败,并出现相同的错误(如果有任何依赖项(。


EDIT@Amberlamps的回答解决了问题,但没有回答为什么会发生这种情况的问题。我的模块模式现在是:

(function(root) {
  // MODULE CODE HERE
  if (typeof module !== 'undefined' && module.exports) { // CommonJS 
    /* var dependencies = require(...) */
    module.exports = myModule;
  } else if (typeof define !== 'undefined' && define.amd) { // AMD
    /* var dependencies...; */
    define([/* dependencies */], function(/* dependencies */) {
      /* Assign closure level vars to respective arguments */
      return myModule;
    });
  } else {
    if (root.hasOwnProperty(/* dependencies */)) {
      /* var dependencies = root... */
      root.myModule = myModule;
    }
  }
})(this);

这使依赖项在不同环境中具有一个通用名称。然而,问题仍然存在:为什么全局对象在闭包的范围内不可用?


EDIT 2我一直在尝试RequireJS和AMD,并更正了上面的代码,以便AMD能够工作。在这种情况下也会发生完全相同的事情:你必须将全局对象显式地分配给闭包中的一个变量,它才能在所述闭包中可用。。。

此模式运行良好。如果您实际使用一个名为super的函数测试它,并通过super()调用它,您可能会遇到错误,因为super是一个保留字。以下代码运行良好:

(function(root) {
    root.super = function() {
        console.log("hello");
    };
}) (window);
(function(root) {
    root.super();
}) (window);

您可以使用window.super()调用您的函数。然而CCD_ 21将导致错误。