如何call/use这个模块在其他JS中files/modules

How to call/use this module in other JS files/modules

最近看了一些JS模块设计模式。我遇到了下面这个小代码片段。

(function(window) {
    var Module = {
        data: "I'm happy now!"
    };

    window.Module = Module;
})(window);

还是不太理解这段代码,我的问题是:

实际上这不是一个模块,而是一个自调用匿名函数或一个立即函数,它在参数中获取一个对象并为其分配 Module 属性:

  • 页面window是传递给这个函数的参数。

  • 所以一个名为 Module 的对象包含 data 属性 被分配给 window.

JavaScript 自调用函数:

A self-invoking expression is invoked (started) automatically, without being called.

Function expressions will execute automatically if the expression is followed by ().

You cannot self-invoke a function declaration.

You have to add parentheses around the function to indicate that it is a function expression

因此,正如您所看到的,无法调用即时函数,因为它的名称表明它将立即执行并且由其自身执行,没有其他函数或范围可以执行它。

要获得更好的参考,请查看:


关于你最后一个关于它的好处和良好做法的问题,如给定 Article reference 所示:

在哪里使用自执行函数?

One obvious situation is when you want to auto-run a function like I showed in above example but that is trivial. If you are in a situation where you want to run a piece of code repeatedly like updating something in the database based on user interaction or fetching records from database every 10 seconds or you want to load new stories via ajax similar to how facebook does on its homepage or some other similar situation, one would normally go for setInterval function something like this:

setInterval(doStuff, 10000);

Above, doStuff function will get called every 10 seconds. That is the normal approach most developers seem to go with. However, there is a huge problem with that.

The setInterval will call doStuff function exactly at specified time of 10 seconds again and again irrespective of whether doStuff function actually finished doing what it is supposed to do. That is bad and will certainly get you into unexpected results.

That is one example of where setInterval is "bad" and should be avoided.

This is exactly where self-executing functions come in handy. We can do the same task with the help of self-executing function along with setTimeout like this:

function foo(){
     // your other code here  
     setTimeout(foo, 10000);
}();

This code will also repeat itself again and again with one difference. setTimeout will never get triggered unless doStuff is finished. A much better approach than using setInterval in this situation.

从另一个文件调用它:

如果这个函数在另一个文件上,如果包含这个文件,它将被自动调用。

为什么我们在JavaScript中使用自调用函数?

如果你问自己为什么要使用这些函数,自调用函数是用来管理Variable Scope.

查看 answer here 了解更多信息。

本例中创建匿名函数的主要原因是为了防止全局对象污染。这不是真正的模块模式。

声明变量时出现问题。如果没有函数范围,变量将被添加到全局对象 (window)。如果要在函数中声明变量。它会在不污染全局对象的情况下将变量添加到函数作用域 window.

发生的情况是 javascript 文件可以添加一个名为 foo 的变量,而在另一个文件上也使用该名为 foo 的变量。除非你真的想让两个 javascript 文件共享一个变量,否则它可能会产生难以修复的冲突和错误。

例如:a.js

var foo = "one"

b.js

var foo = "two"

c.js

alert(foo)

在这种情况下,警告框可能会显示 "one" 或 "two",具体取决于包含 javascript 文件的顺序。

但是有了这个a.js:

(function () {
    var foo = "one"
})()

b.js

(function () {
    var foo = "two"
})()

c.js

(function () {
    alert(foo)
})()

这会产生错误,因为您不能 alert 一个未声明的变量。

检测未定义变量的一种方法是确保在严格模式.

下执行javascript代码

为此,在文件或函数的顶部添加字符串 "use strict"

function () {
  "use strict"
  ...
}

未声明的变量会引发错误,应该可以通过这种方式修复代码。

此外,如果您忘记使用 var 关键字声明变量,即使代码在函数范围内,它也可能最终将变量添加到全局范围。防止全局范围污染的唯一方法是 运行 严格模式下的代码。

在您提供的代码片段中,名为 Module 的模块被显式添加到 window 对象中。您可以从 javascript 中的任何位置访问 window 对象,除非 window 名称被其他变量隐藏。

现在,回到模块。如果要定义modules,可以通过多种方式来完成。例如,您可以在 window 对象上创建一个名为模块的对象。在此对象中,您将插入您的模块。

module.js

window.modules = {}

foo.js

(function (window) {
  var module = {}
  ...
  window.modules.foo = module
})(window)

这个变体不是很好,因为您必须手动将模块添加到 modules 对象。您必须手动修改 window 对象,这可能会出错。

modules.js

window.modules = {}

function define(name, constructor) {
  var module = {exports: {}}
  constructor(module)
  window.modules[name] = module.exports
}

function require(name) {
  return window.modules[name]
}

foo.js

define("foo", function (module) {
  module.exports.one = function () {
    return 1
  }

  module.exports.plus = function (a, b) {
    return a + b
  }
})

bar.js

define("bar", function (module) {
  module.exports = function () {
    var foo = require("foo")
    return foo.plus(foo.one(), foo.one())
  }
})

这是一个模块定义,看起来有点像用 http://requirejs.org/ 定义的模块。这是非常基本的,因为它没有考虑模块依赖性,所以如果 barfoo 之前加载和使用。然后 require 方法将无法 return 模块。

此外,如果你想存储模块而不让它们在全局范围内可见,你只能在 window 对象上定义 requiredefine 方法并隐藏模块进入这样的匿名范围:

  (function (window) {
    var modules = {}

    function define(name, constructor) {
      var module = {exports: {}}
      constructor(module)
      modules[name] = module.exports
    }

    function require(name) {
      return modules[name]
    }

    window.define = define
    window.require = require
  })(window)

这样,definerequire 是唯一可以让您访问模块的函数。如果不首先要求其他模块,其他模块将无法修改其他模块。这在使用可能与您的模块系统冲突的第三方脚本时很有用。