【问题标题】:Passing a window object into Javascript namespace将窗口对象传递到 Javascript 命名空间
【发布时间】:2016-02-01 04:38:28
【问题描述】:

我试图更好地理解 javascript 中的命名空间,并找到了一个将窗口对象作为参数的 javascript 立即调用函数表达式的示例。这是其中的代码:

var CG = CG || {};
CG.main = (function(window) {
    var FOCAL_LENGTH = 8.0;
    var context, width, height, startTime;

    var init = function() {
        var element = document.getElementById("canvas1");
        context = element.getContext("2d");

        width = element.width;
        height = element.height;

        startTime = (new Date()).getTime() / 1000.0;
        tick();
    }

var original_onload = window.onload || function() {};
    window.onload = function() {
        original_onload();
        CG.main.init();
    }
    return {
        init: init,
        draw: draw_shape,
        clear: clear_canvas
    };
}(window));

在命名空间定义的末尾,括号中有一行窗口,我对它的功能感到困惑。我认为将 window 参数添加到定义末尾的目的是将全局 window 变量绑定到命名空间,然后将不同的属性添加到窗口,但我不能确定。

在另一个例子中,有一个随机变量名传入命名空间的定义中,在命名空间定义的最后,命名空间的实际名称作为参数传递:

var namespace = namespace || {};
// here a namespace object is passed as a function
// parameter, where we assign public methods and
// properties to it
(function( o ){
    o.foo = "foo";
    o.bar = function(){
        return "bar";
    };
})(namespace);
console.log(namespace);

所以这里真的有几个问题:

  1. 在命名空间定义末尾传递参数有什么作用?

  2. 如果我对这一切如何运作的直觉不正确,那么这种命名空间创建 javascript 的一般结构是什么?

显然我对此很陌生,因此我们将不胜感激,谢谢。

【问题讨论】:

  • 这只是一个对象作为参数传递给函数。它没有什么特别之处。
  • 使用您的第二个示例代码,将其重写为您习惯的函数,而不是 IIFE。括号现在是什么意思?

标签: javascript namespaces


【解决方案1】:

我会尽力解释这一点,但我对它的理解来自 Kyle Simpson。他很厉害,你应该看看他。 :-D

您正在询问有关立即调用的函数表达式 (IIFE)、向它们传递参数以及为什么有人会这样做的问题。

首先,在这种情况下使用 IIFE 的原因是为了限制变量的范围。

这很重要,因为随着程序变得越来越大,并且添加了许多片段,您很容易从一个变量到另一个变量发生冲突。

app.js 可以有

variable = "thing";

不久之后 someelse.js 可能有

variable = "not thing";

这是个大问题。在 javascript 中通过创建立即运行并运行一次的“模块”或函数来避免这种情况。

这样,您在函数中创建的变量和方法不会“污染全局范围/命名空间”。

但是,如果您需要或想要在全局窗口对象上可用的东西怎么办?

好吧,您可以通过将其添加到“窗口”中来做到这一点,该窗口是 javascript 中的全局范围。

(function Module(window){
   var _thing = "private thing that only exists in this function";
   window.thing = _thing;
      //IS NOW AVAILABLE GLOBALLY AND EXPLICITLY ON WINDOW OBJECT
      //window.onload you can wait for DOM/page before running the rest
})(window);

你也可以在你的函数中任意命名它:

(function niftyModule(global){

    global.variable = "nifty text!";

})(window)

当您使用多个库时,这一点变得尤为重要。

出于某种原因,每个人都喜欢使用“$”作为他们库的表示,这样您就可以访问他们的私有方法(它们实际上也只是 IIFE 中的函数!(它是一种非常流行的构建好东西的方法)。

那么,如果您使用 jQuery 和其他 2 个也使用 $ 访问其公共方法/api 的库怎么办?

很简单,您可以通过将其作为参数传入来分配要在函数/模块范围内分配哪个变量!

(function NiftyModule(window, $){

 //Now, every time you use $ in here it means jQuery and not something else!

})(window, jQuery);

玩转函数和范围很重要。以不同的方式构建一些变量。

例如,是....

var text = "nifty text";

text = "nifty text";

如果你在函数内部做同样的事情呢?这两个版本有何不同?

另外,要习惯于在 IIFE 中构建自己的程序,并适当限制所编写代码的范围。

您还可以从具有您希望全局访问的方法和变量的函数返回对象,而无需将它们添加到窗口对象中。

一开始很复杂,但是以后会省去很多麻烦和bug!

最后,在你的例子中:

//initialize a global variable called namespace. If this already
//existed then assign it the previous values. If not, make it an empty
//object.
var namespace = namespace || {};

//pass namespace into an IIFE. Within the IIFE refer to namespace as "o"
(function( o ){
    //assign a variable to namespace
    o.foo = "foo";

    //assign a method to namespace
    o.bar = function(){
        return "bar";
};
})(namespace);

//now when you log namespace it will have those properties.
console.log(namespace);

【讨论】:

  • 首先,感谢您的回答!它非常清晰简洁,直接解决了我的问题!我只是有一个后续问题。我还了解到命名空间也可以使用来自this 链接的文字函数对象来完成,您对何时使用每种方法有什么建议吗?
  • 现在,您应该始终使用链接中的方法。返回一个对象(创建一个公共 API)。在您对范围感到满意之前,请避免一起使用窗口并强迫自己真正了解正在发生的事情。
猜你喜欢
  • 2012-11-30
  • 2013-10-25
  • 2011-03-04
  • 1970-01-01
  • 1970-01-01
  • 2012-01-21
  • 2016-09-22
  • 2013-06-01
  • 2013-06-07
相关资源
最近更新 更多