理解javascript全局命名空间和闭包

时间:2012-03-19 16:28:55

标签: javascript namespaces closures global-variables

我正在努力提高我对javascript中全局命名空间的理解,我对一些事情感到好奇:

  1. 是否存在“GOD”(即父级)对象,所有对象(因为除了基元之外的所有东西都是对象)才能回答,如果是,那么该对象是“窗口”吗?

  2. 为什么在全球范围内拥有变量/功能是不明智的?

  3. 如果在全局范围内拥有变量/函数真的是个坏主意那么闭包是避免这种情况的最佳方法吗?例如:

    function parent(){
        var x = 'some value';//this var would be considered global to all children functions but not in the true global namespace
        function child1(){
            x.someMethod()
        } 
        function child2(){
            x*something;
        }
        function child3(){
            x+=something;
            child2()
            child1()
        }
        child3()
    }
    parent()
    

4 个答案:

答案 0 :(得分:24)

  1.   

    是否有 god (即父母)对象?

    Yes.从技术上讲,它是所有这些原语都是其成员的全球对象;只是在浏览器中,window对象全局对象。

    > window.String === String;
    true
    
  2.   

    为什么在全局范围内拥有变量/函数是不错的主意?

    因为如果您要添加大量第三方库/脚本,它们都共享相同的全局对象,则可能存在名称冲突。这是使用$作为别名(jQuery,Prototype等)的所有库的真实问题。

  3.   

    如果在全局范围内拥有vars /函数真的是个坏主意那么闭包是避免这种情况的最佳方法吗?

    x不应被视为全球性的。它是通过在parent()函数中声明子函数而形成的闭包的一部分。您的代码段的问题部分是parent()是全局的;如果其他一些代码重新声明parent()会发生什么?这会更好:

    (function () {
    
    function parent(){
        var x = 'some value';
        function child1(){
            x.someMethod()
        } 
        function child2(){
            x*something;
        }
        function child3(){
            x+=something;
            child2()
            child1()
        }
        child3()
    }
    parent()
    
    }());
    

    在子函数中可以访问事实x并不错;你应该自己编写这些函数,所以你应该意识到存在x。请注意,如果您使用x在这些子功能中重新声明var,则不会影响x中的parent()

答案 1 :(得分:5)

  1. 是的,在浏览器环境中,“上帝对象”是窗口。它通常称为全局对象,而不是上帝对象;)在非浏览器环境(如nodejs)中,全局对象可能使用除窗口之外的其他名称。

  2. 如果将所有内容都设置为全局变量,则可能会遇到冲突的名称。还有encapsulation的问题 - 换句话说,通过将变量放入需要它的范围,你的代码通常会更好。

  3. 是的,这几乎是首选方法。您也可以使用IIFE

答案 2 :(得分:3)

  1. 据我所知,我会说是,窗口是父对象。但是,在Iframe中你有自己的窗口对象,不同于你可以通过window.parent访问的周围窗口.parent

  2. 由于潜在的名称冲突导致很多全局var,因此很难检测到错误。一般来说,设计一些命名空间更安全(参见 来自jQuery的$等)和模块化代码。

  3. 请注意,parent是潜在的窗口现有字段。这个采取appart,功能是对象,因此观察结果与2)相同。

答案 3 :(得分:3)

如果您需要将变量放在全局命名空间中,并且您可能会在某个时刻创建单个对象变量并将其他变量作为属性或方法添加到其中。给对象一个不太可能被其他人使用的名称(诚然,这是碰撞问题出现的地方,但可以通过仔细,标准化的命名来减轻这种情况。)

e.g。而不是:

var thing1 = 'table';
var anotherthing = 'chair';
var mypet = 'dog';
var count = 4;
var show_something: function( _txt ) { return _txt.trim(); };

这样做:

var cmjaimet_obj = {
  thing1: 'table',
  anotherthing: 'chair',
  mypet: 'dog',
  count: 4,
  show_something: function( _txt ) { return _txt.trim(); }
};

然后将它们称为属性:

e.g。而不是:

count += 2;
anotherthing = 'sofa';
console.log( show_something( 'Thing: ' + anotherthing ) );

这样做:

cmjaimet_obj.count += 2;
cmjaimet_obj.anotherthing = 'sofa';
console.log( cmjaimet_obj.show_something( 'Thing: ' + cmjaimet_obj.anotherthing ) );