高级Javascript初始化

时间:2013-10-01 00:49:51

标签: javascript

我无法破译以下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次。有人可以解释一下这样翻转它的意思吗?

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.

})();