模式
(function (foo) {
...code...
foo.bar = baz;
...more code...
}(window.FOO = window.FOO || {});
您所描述的模式没有正式名称,因为它是三个独立的模式组合而成。每个模式都有多个名称,但在本文中,我将使用以下术语:
闭包
整个模式的基础是闭包
。它只是一个用于限定变量和函数的作用域的函数,以使它们不会污染全局命名空间:
无闭包
//these declare window.foo and window.bar respectively
//as such, they pollute the global namespace
var foo;
function bar() {}
在这种情况下,Closure是指
立即执行函数表达式(IIFE)。
(function () {
var foo;
function bar() {}
}());
闭包内保留变量的优点在于,您不必担心其他人会覆盖您正在使用的变量。对于经常使用的临时变量,如
i
或
j
,这尤其重要。
别名
此模式的第二个重要部分是别名。别名允许在闭包内定义和使用变量,而无需担心它所属的全局命名空间。
没有别名
(function () {
...
foo = window.SomeFunction(bar, baz);
...
}());
使用别名
(function (sf) { //local name
...
foo = sf(bar, baz);
...
}(window.SomeFunction)); //global namespace
这一点尤其重要,因为它意味着可以通过在单个位置更改名称,在整个大型JavaScript文件中更改全局命名空间。这是一个好事™。此外,缩小器可以将内部别名缩短为单个字母变量名,例如
a
,从而在缩小时节省大量字节。
命名空间扩展
命名空间扩展模式依赖于或运算符(||
)的合并行为。在许多语言中,&&
和||
返回true
或false
,但在JavaScript中,&&
返回第一个falsey
值(false
,0
,''
,null
,undefined
),||
返回第一个truthy
值(任何不是falsey
的东西)。对于两个运算符,如果未找到相应类型,则返回最后一个参数。这使得||
运算符成为仅在不存在时定义新命名空间的方便方法。
没有命名空间扩展
if (typeof window.Foo === 'undefined') {
window.foo = {};
}
使用命名空间扩展
window.foo = window.foo || {};
这很有用,因为它允许命名空间扩展附加属性和方法,而不必担心这些属性和方法的定义顺序。
在第一个示例中,需要在执行
FileB
之前执行
FileA
。
FileA.js
window.foo = {};
window.foo.bar = 'baz';
FileB.js
window.foo.fizz = 'buzz';
在这个第二个例子中,
File1
和
File2
可以以任何顺序执行:
File1.js
window.foo = window.foo || {};
window.foo.bar = 'baz';
File2.js
window.foo = window.foo || {};
window.foo.fizz = 'buzz';
一起来
将每个模式结合在一起可以创建一个非常强大的模块化脚本:
(function (foo) {
var i,
len,
internal,
qux;
foo.bar = function () {...};
}(window.FOO = window.FOO || {}));
FOO
。这将隐藏window.FOO
,除非你使用window.FOO
显式地引用它。 - icktoofayalert(window.FOO === foo); // true
没有技术名称。它取决于它的用途。如果你要暴露一个库,称其为你的库。如果你要导出一个Foo
构造函数,请称其为Foo
构造函数。 - I Hate Lazywindow.FOO
;我总是引用它的Alias
(感谢zzzzBov)。所以,使用FOO
对我来说是可行的。@pst谢谢您提供的链接!很抱歉我错过了那个帖子。@user1689607感谢你的澄清,我非常感谢!感谢大家的帮助......我欠你们几瓶俄勒冈小麦酒。 :) - mhulse