我无法破译以下Javascript初始化声明:
(function(NAMESPACE) {
NAMESPACE.nav = {};
var nav = NAMESPACE.nav,
_init = false,
_isNavOpen = false,
_inner = document.getElementById('inner-wrap');
// constants
nav.CLASS = 'js-nav-open';
nav.CLASS_READY = 'js-nav';
nav.CONTAINER = '#nav';
nav.DURATION = 400;
nav.HAS_CSSTRANSITIONS = $('html').hasClass('csstransitions') && $('html').hasClass('csstransforms3d');
... ...
// toggle open/close
nav.toggle = function(event) {
event.stopPropagation();
if(_isNavOpen && $('html').hasClass(nav.CLASS)) {
nav.close();
} else {
nav.open();
}
// this is for the links
if(event) {
event.preventDefault();
}
};
}(PROJECT_NAME));
似乎不必要的复杂 - 在2行中调用(或设置?)'nav'3次。有人可以解释一下这样翻转它的意思吗?
答案 0 :(得分:4)
这是一个JavaScript闭包的示例,它通常用于创建私有作用域并避免让对象污染全局作用域。
以这种方式创建插件是非常常见的,以避免由于具有相同名称的变量等而与页面上的其他功能发生冲突。本质上,它是一种管理范围的机制。
答案 1 :(得分:4)
这是使用jQuery时的常见做法:
(function ($) {
var div = $('#my-div');
// Etc
}(jQuery));
将脚本包装在闭包中确保某些变量将具有您期望的值。
例如,jQuery使用$
来完成所有事情。大多数人都喜欢使用$('do something')
而不是jQuery('do something')
。
但是说你在页面上有另一个库,它也使用全局变量$
。
通过将代码包装在闭包中,您将$
保留为jQuery,并单独使用jQuery。 (当您将jQuery
作为参数传递给闭包时,$
只能 表示“jQuery”,在此函数的范围内。)
同样,在您的示例中,您要保留NAMESPACE
变量。即使有另一个名为NAMESPACE
的变量,在页面的其他位置引起一个球拍,通过在闭包的末尾传入一个变量,你将保证NAMESPACE
将是你期望的对象它(至少在闭幕式内)。
假设您有一个名为AbominableSnowman
的全局变量,但您希望使用AS
作为快捷方式。通过这样做:
var AS = "Apple Soup";
(function (AS) {
AS.tellMeAboutSnowmen();
alert(AS.snowballs);
}(AbominableSnowman));
您的代码仍将按预期运行。 (证明:http://jsfiddle.net/RUzZH/1/)
至于“翻转它”,似乎原始程序员想要将NAMESPACE.nav
缩短为nav
。这可能是最好的方法。
另一种选择(不推荐):
// It's best to limit your assignments to 1-per-line
// This kind of code isn't fun to debug, or even read
var nav = NAMESPACE.nav = {};
这似乎不值得担心。但是,由于此脚本经常与NAMESPACE.nav
进行交互,因此使用.nav
变量直接引用nav
属性会略微快一点。 (这实际上是一种微观优化,但在这种情况下,为了清晰起见,它的方便地由于不同的原因而合理。)
答案 2 :(得分:3)
这是一个逐行解释(标题只是为了解析它):
<强>设置强>:
// Create an anonymous function expression taking `NAMESPACE` as a parameter.
// Likely the *real* namespace will be passed to the function at the end
// with ... })(realnamespacetomodify);
(function(NAMESPACE) {
// Create the new part of the namespace. Note that we are editing a reference
// so really this change happens on whatever object was passed in.
NAMESPACE.nav = {};
// Create a local pointing to this new sub-namespace. Probably just for
// convenience, also possibly for portability (if the name is used in closures,
// then those closures don't need to refer to NAMESPACE directly).
var nav = NAMESPACE.nav,
模块定义:
// While nav refers to an object likely in global scope, nav itself can
// never be referred to from global scope because it is a local here.
// These variables are local here. They can never be referred to by global scope.
_isNavOpen = false,
_inner = document.getElementById('inner-wrap');
// These variables, added to nav, can be accessed using the object that
// nav refers to in global scope (see the end).
nav.CLASS = 'js-nav-open';
...
// This function is also added to nav, therefore it can be accessed outside
nav.toggle = function(event) {
...
// This reference to _isNavOpen resolves because this function
// is a closure, and binds variables outside its scope
// to the function itself. So even though _isNavOpen can't be
// accessed globally, it can be accessed here, making it like
// a private member of this namespace.
if(_isNavOpen && $('html').hasClass(nav.CLASS)) {
// nav is also bound by the closure and can be accessed here
nav.close();
} ...
};
在全球空间中使用:
}(PROJECT_NAME));
console.log(PROJECT_NAME.nav.CLASS); // "js-nav-open"
console.log(PROJECT_NAME.nav.toggle); // Function object
这是一个模块模式。使用它有几个原因:
至于前三行本身(您的原始问题),他们可以直接引用PROJECT_NAME
,但看起来它已被设置为帮助代码可移植性< / strong>即可。您会注意到匿名函数本身从不指向真实对象(PROJECT_NAME
)。这意味着您可以复制并粘贴此部件,并仅在一个位置更改该引用。
另一个答案提到了范围,虽然这也很重要,但它没有解释这个代码的所有好处,例如为什么它不直接引用现有的全局变量。范围隐藏的好处本身是通过这部分模式实现的:
(function() {
... // Anything set here is local, not global.
})();