看一些JavaScript库和其他人的代码,我看到了两种常见的模式,我不知道使用其中一种模式是否存在差异或优势。模式看起来像这样:
1
var app = (function () {
// Private vars
// Module
var obj = {
prop: "",
method: function () {}
};
return obj;
})();
2
(function () {
// Private vars
// Module
var obj = {
prop: "",
method: function () {}
};
window.app = obj;
})();
这些模式是相同的还是其中一种比另一种更有优势或用途不同?
提前致谢。
答案 0 :(得分:5)
第二个假设在父作用域中存在一个名为window
的对象,并在那里指定一个属性。
第一个将它留给调用者进行赋值,并且不依赖于被定义的window
(它可能只在Web浏览器中)。
所以,我会说第一个肯定更好(更独立,更少依赖环境)。
答案 1 :(得分:2)
tl; dr:选择一种方法并保持一致。
在我看来,第一种方法在可读性方面略有优势。在我的脑海中,当我阅读它时,我看到,“模块app
正在被定义,”并且此闭包内的所有内容都属于该模块。这对我来说是一种自然的分解,并强加了即将定义的模块的面向对象特性。
我赞成第一种方法的另一个原因是更改模块定义的范围更清晰。您定义的每个模块都不需要成为全局范围的一部分。使用第二种方法,如果未通过传递父对象注入作用域Jared Farrish用他的jQuery示例说明,那么如果您决定更改该父对象的名称,则存在破坏代码的风险。这个例子说明了这一点:
var namespace = {
subns: { ... }
};
(function() {
var module = { ... };
namespace.subns.someModule = module;
}());
只要标识符namespace
或subns
发生更改,您还必须更新此模块以及遵循此模式的任何其他模块,并将其自身添加到同一对象。
总而言之,方法一和方法二(依赖注入)都不比另一方“更好”,这只是一个偏好问题。这次讨论的唯一好处是你应该选择一种方法并保持一致。
答案 2 :(得分:1)
他们都在完成同样的事情,在运行代码时在全局命名空间中创建一个对象。
其中一个并不比另一个更“硬编码”,因为它们都没有进行任何类型的函数原型设计,您可以使用new关键字创建对象的克隆。在我看来,这只是一个偏好问题。
例如,jquery做了类似于后者的事情:
(function( window, undefined ) {
// Use the correct document accordingly with window argument (sandbox)
var document = window.document;
var jQuery = (function() {
// Define a local copy of jQuery
var jQuery = function( selector, context ) {
// The jQuery object is actually just the init constructor 'enhanced'
return new jQuery.fn.init( selector, context, rootjQuery );
},
// Map over jQuery in case of overwrite
_jQuery = window.jQuery,
// Map over the $ in case of overwrite
_$ = window.$,
...
但Prototype JS Library是前者:
var Prototype = {
Version: '1.6.1',
Browser: (function(){
var ua = navigator.userAgent;
var isOpera = Object.prototype.toString.call(window.opera) == '[object Opera]';
return {
IE: !!window.attachEvent && !isOpera,
Opera: isOpera,
WebKit: ua.indexOf('AppleWebKit/') > -1,
Gecko: ua.indexOf('Gecko') > -1 && ua.indexOf('KHTML') === -1,
MobileSafari: /Apple.*Mobile.*Safari/.test(ua)
}
})(),
...
我不知道为什么一个比另一个更好,或者他们以不同方式完成任务(在窗口命名空间中创建app对象)。
答案 3 :(得分:0)
在第一个示例中,如果app
在另一个函数中定义,app
仅在该局部范围内可用,而在第二个示例中,app
变量显式分配给全球范围。
在第二个示例中,app
仅在函数外部的全局范围中定义时才会分配给全局范围。
答案 4 :(得分:-2)
第二种形式有一个小优势,因为你有一个完全自包含的功能;例如,您可以为JS文件设置标准页眉和页脚。
我没有完全售出的部分是块内的局部变量。我倾向于这样:
(function () {
// Private vars
// Module
window.app = {
prop: "",
method: function () {}
};
})();
虽然当你做的不止一件事情时会出现故障,例如用多个方法而不是像这个例子中的单个对象构建一个对象。