Javascript 如何为每个JS文件使用闭包,但仍然让文件相互交互。
我知道使用闭包(IIFE)是最佳实践,因为它可以防止污染全局名称空间。但是,当我将闭包添加到文件中时,它阻止了我的第二个文件(controllers.js)读取第一个文件(models.js)。给你一个想法,下面是它们的样子: models.jsJavascript 如何为每个JS文件使用闭包,但仍然让文件相互交互。,javascript,closures,iife,Javascript,Closures,Iife,我知道使用闭包(IIFE)是最佳实践,因为它可以防止污染全局名称空间。但是,当我将闭包添加到文件中时,它阻止了我的第二个文件(controllers.js)读取第一个文件(models.js)。给你一个想法,下面是它们的样子: models.js ;(function() { function searchResult (obj) { this.state = obj.State; /*Do more stuff */ } })(); ;(function() {
;(function() {
function searchResult (obj) {
this.state = obj.State;
/*Do more stuff */
}
})();
;(function() {
function storeSearchResults(jsonObj) {
var instance = new searchResult(jsonObj.data[i]);
/* Do more */
}
})();
controllers.js
;(function() {
function searchResult (obj) {
this.state = obj.State;
/*Do more stuff */
}
})();
;(function() {
function storeSearchResults(jsonObj) {
var instance = new searchResult(jsonObj.data[i]);
/* Do more */
}
})();
现在我已经在它们上添加了闭包,我得到了一个错误,searchResult
在controllers.js中没有定义——因为它看不到它存在于models.js中。如何让它理解它存在于另一个文件中
是的,models.js是在controllers.js文件之前添加到HTML文件中的。要让它们进行交互,它们必须有一些公共符号。您有两个选择:
;(function(globals) {
var MyApp = globals.MyApp = globals.MyApp || {};
MyApp.searchResult = searchResult;
function searchResult (obj) {
this.state = obj.State;
/*Do more stuff */
}
})(this);
这是因为在松散模式下,全局范围内的这个
是全局对象(浏览器上的窗口
)。我们将其作为参数globals
传递到IIFE中,然后在其上使用或创建名为MyApp
的属性,并将searchResult
作为属性添加到其中
controllers.js:
;(function(globals) {
var MyApp = globals.MyApp = globals.MyApp || {};
function storeSearchResults(jsonObj) {
var instance = new MyApp.searchResult(jsonObj.data[i]);
/* Do more */
}
})(this);
;
function storeSearchResults(jsonObj) {
var instance = new searchResult(jsonObj.data[i]);
/* Do more */
}
我们做了同样的事情,只是controllers.js
希望models.js
已经运行。尽管我们仍然执行var MyApp=globals.MyApp=globals.MyApp | |{}如果没有运行models.js
,那么新的MyApp.searchResult
当然会失败
这个主题可能有十几种语法变体,这只是其中之一
使用某种能为你做这件事的图书馆
您的另一个选择是使用库(其中的一个全局符号是require
,它是一个函数)或任何其他库
你自己用另一种方式做
另一个DIY选项完全摆脱了全局,你甚至不需要一个全局
要做到这一点,您的单个文件没有iLife(尽管它们可以将iLife用于不想与其他文件共享的内容):
controllers.js:
;(function(globals) {
var MyApp = globals.MyApp = globals.MyApp || {};
function storeSearchResults(jsonObj) {
var instance = new MyApp.searchResult(jsonObj.data[i]);
/* Do more */
}
})(this);
;
function storeSearchResults(jsonObj) {
var instance = new searchResult(jsonObj.data[i]);
/* Do more */
}
然后你用一个缩微器把你的脚本组合起来,并把它们包装成一个大生命。您可能有pre.js
:
(function() {
})();
和post.js
:
(function() {
})();
然后minifier通过组合pre.js+models.js+controllers.js+post.js
创建app.js
。最终结果(为便于阅读,此处未缩小并格式化)为:
我称之为DIY,但如果有工具可以帮助我,我不会感到惊讶。事件和侦听器传递和接收数据
我不使用globals
然而,我不知道如何在原始javascript中使用事件,或者是否可以完成数据传递。我使用jquery/node,它允许传递数据,而且工作非常出色。您可以使用模块系统,如(AMD)或(CommonJS)。谢谢@TJ,您解决了我的问题!为了理解,我有两个问题:1)每个生命结束时的(这个)
参数是为了什么?2.controllers.js
如何理解从何处获取全局
参数——因为没有人显式调用它?@ayjay:在脚本
块的顶层,如果您没有使用“use strict”
,这是全局对象(浏览器上称为window
;从技术上讲,window
是全局对象的一个属性,它是一个全局变量,用于引用自身)。因此,通过将这个
传递到我们的IIFE中,我们可以用参数名全局
引用它(我通常使用“use strict”
在iLife的顶部,因此函数中的代码是严格模式,因为严格模式非常方便。但是在iLife之外,我喜欢使用这个窗口,而不是窗口,因为它不是特定于浏览器的。谢谢,我还有一个后续问题…你选择3级深度定义有什么原因吗(即,global.MyApp.searchResult
)而不是2(即,global.searchResult
)?我想知道使用3级是否是一种最佳实践方法。@ayjay:所以我们只有一个全局:MyApp
。我认为我在上面代码中对参数的命名非常混乱(我在中使用了global
)“全局对象”包含全局变量),因此我将其更改为globals
(因为“全局对象”包含全局变量)另外,我在设置全局变量的位前面添加了一个var MyApp=
。MyApp
这样我们就可以在iLife中使用MyApp
。同时更新了pastie:我们在globals
上放置的任何属性都会成为全局变量,所以我们希望将其保持在最小值(如果可能,为零,上面的一个)。我还有一个问题与您提供的答复有关(顺便说一句,我非常感谢所有的答复)。在处理文件之间的名称空间时,哪种方法更常用:或者?我了解这两种方法都有效,但我很好奇在现实世界中更遵循哪种约定。