高级 JavaScript 初始化
Advanced Javascript initialisation
我在破译以下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));
这似乎不必要地复杂 - 呼叫(或设置?"导航"在 3 行中 2 次。有人可以解释一下这样翻转它有什么意义吗?
这是 JavaScript 闭包的一个示例,通常用于创建私有作用域并避免对象污染全局作用域。
以这种方式创建插件以避免由于具有相同名称的变量等而导致与页面上的其他功能发生冲突是很常见的。 本质上,它是一种管理范围的机制。
这是使用 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
属性会稍微快一点。(这确实是一种微优化,但在这种情况下,出于不同的原因[为了清楚起见],它是方便合理的。
这是一个逐行的解释(标题只是为了分解它(:
设置:
// 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
,但看起来它已被设置为帮助代码可移植性。 您会注意到匿名函数本身从不指向真实对象(PROJECT_NAME
(。 这意味着您可以复制并粘贴此部分,并且仅在一个位置更改该引用。
另一个答案提到了范围,虽然这也很重要,但它并没有解释这段代码的所有好处,比如为什么它不只是直接引用现有的全局变量。 范围隐藏的好处本身是通过这部分模式实现的:
(function() {
... // Anything set here is local, not global.
})();
- 正在使用日期字符串初始化javascript日期对象
- 使用变量初始化javascript数组
- 在初始化Javascript时执行的私有函数中设置公共属性
- 如何在网页上初始化javascript
- 使用angularjs范围变量初始化javascript变量
- 如何使用非零索引初始化 Javascript 数组
- 是否可以在一行代码中定义和初始化JavaScript中的多维数组
- 用零初始化 JavaScript 数组
- 当 prompt() 方法用于初始化 javascript 中的变量时,初始化变量的类型是什么
- 在Razor中初始化JavaScript数组
- 正在服务器端初始化JavaScript变量
- 使用大型客户端数据初始化JavaScript应用程序
- 使用||和{}初始化javascript变量
- 如何呈现PHP输出来初始化JavaScript中的变量
- 如何用HTML代码直接初始化javascript中的变量
- 使用[]初始化javascript变量和使用{}初始化变量有区别吗?
- 基于用户输入初始化JavaScript数组
- jQuery初始化JavaScript动作
- 如何使用表单初始化JavaScript
- 我应该何时初始化javascript属性