了解JavaScript全局命名空间和闭包

understanding the javascript global namespace and closures

我正在努力提高对JavaScript中全局命名空间的理解,我对以下几点很好奇:

  • 是否有一个"上帝"(即父母)的对象,所有的对象(因为除了原语以外的所有东西都是对象)都要回答,如果是这样,那个对象会是"窗口"?

  • 为什么在全局级别设置vars/函数是个坏主意?

  • 如果在全局范围内使用vars/函数真的是一个坏主意,那么闭包是避免这种情况的最佳方法吗?例子:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    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()

  • Is there a god (i.e. a parent) object?

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

    1
    2
    > window.String === String;
    true
  • Why is it bad idea to have vars/functions on a global level?

    因为如果您要添加许多第三方库/脚本,它们都共享同一个全局对象,那么就有可能发生名称冲突。这是所有使用$作为别名(jquery、原型等)的库的实际问题。

  • If it is really a bad idea to have vars/functions in global scope then would closures be the best way to avoid this?

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    (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的存在。记住,如果您在使用var的子函数中重新声明x,则不会影响parent()中的x


  • 是的,在浏览器环境中,"上帝对象"是窗口。它通常被称为全局对象,而不是上帝对象;)在非浏览器环境(如nodejs)中,全局对象可能使用其他名称而不是window。

  • 如果你把所有东西都看成是全局的,你就有可能碰到互相碰撞的名字。还有封装的问题——换句话说,通过只将变量放在需要的范围内,您的代码通常会更好。

  • 是的,这几乎是首选的方法。你也可以用生活用品


  • 如果需要将变量放在全局命名空间中,并且在某个时刻可能会创建单个对象变量,并将其他变量作为属性或方法添加到该变量中。给对象一个不可能被其他人使用的名称(诚然,这是发生冲突问题的地方,但可以通过谨慎、标准化的命名来减轻冲突问题)。

    例如,代替:

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

    这样做:

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

    然后将其称为属性:

    例如,代替:

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

    这样做:

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

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

  • 由于可能发生名称冲突,因此很难检测到错误,所以使用大量的全局var是一个坏主意。一般来说,设计一些名称空间更安全(请参见jquery等的$和模块化代码。

  • 注意,parent是一个潜在的现有窗口领域。这一采取的装置,功能是对象,所以相同的观察比在2)适用于这里。