我最近阅读了一些 JS 模块设计模式。我遇到了这个小代码片段,如下所示。
(function(window) {
var Module = {
data: "I'm happy now!"
};
window.Module = Module;
})(window);
还是不太明白这段代码,我的问题是:
- 如何在这个特定的 JS 文件之外使用/调用这个模块?需要我 给这个模块分配一个变量?例如var module1 = (...)(...);
- 谁能解释一下这里的 window 参数代表什么?
- 在项目中包含两/三个这样的模块是一种好习惯吗? 同一个文件?
最佳答案
在这种情况下创建匿名函数的主要原因是为了防止全局对象污染。这不是真正的模块模式。
当你声明一个变量时,问题就出现了。如果没有函数范围,变量将被添加到全局对象(窗口)中。如果您要在函数中声明变量。它会将变量添加到函数范围内,而不会污染全局对象窗口。
发生的情况是,一个 javascript 文件可以添加一个名为 foo
的变量,并在另一个文件上使用名为 foo
的变量。除非你真的想让两个 javascript 文件共享一个变量,否则它可能会产生难以修复的冲突和错误。
例如:a.js
var foo = "one"
b.js
var foo = "two"
c.js
alert(foo)
在这种情况下,警报框可能会显示“一”或“二”,具体取决于包含的 javascript 文件中的顺序。
但是有了这个 a.js:
(function () {
var foo = "one"
})()
b.js
(function () {
var foo = "two"
})()
c.js
(function () {
alert(foo)
})()
这会产生一个错误,因为您不能 alert
未声明的变量。
检测 undefined variable 的一种方法是确保以严格模式执行javascript代码。
为此,请在文件或函数的顶部添加字符串 "use strict"
。
function () {
"use strict"
...
}
未声明的变量会引发错误,应该可以通过这种方式修复代码。
此外,如果您忘记使用 var
关键字声明变量,即使代码的作用域是函数,它也可能最终将变量添加到全局作用域。防止全局范围污染的唯一方法是在严格模式下运行代码。
在您提供的代码片段中,名为 Module 的模块被显式添加到窗口对象中。您可以从 javascript 中的任何位置访问窗口对象,除非窗口名称被其他变量隐藏。
现在,回到模块。如果要定义模块,可以通过多种方式完成。例如,您可以在称为模块的窗口对象上创建一个对象。在此对象中,您将插入您的模块。
模块.js
window.modules = {}
foo.js
(function (window) {
var module = {}
...
window.modules.foo = module
})(window)
这种变体不是很好,因为您必须手动将模块添加到 modules
对象。您必须手动修改窗口对象,这可能会出错。
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/ 定义的模块。 .这是非常基本的,因为它没有考虑模块依赖关系,所以如果 bar
在 foo
之前加载和使用。那么 require
方法将无法返回模块。
另外,如果你想存储模块而不让它们在全局范围内可见,你只能在窗口对象上定义 require
和 define
方法并隐藏模块进入这样的匿名范围:
(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)
这样,define
和 require
是唯一可以让您访问模块的函数。其他模块将无法修改其他模块而不需要它们。这在使用可能与您的模块系统冲突的第三方脚本时很有用。
关于javascript - 如何在其他 JS 文件/模块中调用/使用该模块,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32100376/