Javascript 命名空间

11

我希望通过将JavaScript代码拆分为不同的文件并给每个文件一个 "sub" 命名空间来使其更加模块化,如下所示。

subA.js

if(typeof ex == "undefined") {
    var ex = {};
}

ex.subA = function() {
//all functions of subA here
}

同样适用于 subB 等。

目前我只有一个文件,ex.js

var ex = (function() {
    //private vars/funcs
    return {
        //public vars/funcs
    }
})();

看起来我应该将大部分函数移动到 subA.js 和 subB.js 中,但仍然在开头包含 ex.js,随后是 subA.js 和 subB.js。

我有几个问题。

  1. 我很难记住我如何制作最初的命名空间文件 ex.js。它看起来匿名函数最初是用来使一切都是私有的,但我不记得为什么需要将其括在括号中,并使用末尾的 (); 直接执行。

  2. 继续 q1,我的子文件是否应与 ex.js 具有相同的格式,即将匿名函数包装在括号中并立即执行?

  3. 看起来子文件只能访问 ex 的公共函数,这是真的吗?如果是这样,我如何允许我的子文件也访问私有函数?

  4. 在我的 HTML 文件中,在我的 document.ready 函数(jQuery)中,我应该将 ex 初始化为一个变量,还是可以通过以下方式逐个调用每个函数

$(document).ready(function() {
    ex.doSomething();
    ex.doSomethingElse();
}

两者之间有区别吗?我认为当 ex.js 被包含时,由于匿名函数被立即执行,全局变量 ex 将立即创建,因此我不需要在 document.ready 中重新定义它。

  1. subA.js 中的第一个 if 语句与 var ex = ex || {}; 有什么区别?哪个更好?

  2. 您使用什么 JavaScript 代码风格标准?

如果你读完了这些,你已经值得一个赞了,干杯。


最好在你的 typeof 比较中添加引号,并删除 !exif(typeof ex == "undefined") - Rob W
@Rob W,有些浏览器返回null而不是“undefined”,对吗?Yahoo的命名空间代码使用!ex。 - Michael
当一个变量在之前从未被定义过时,typeof 将返回 "undefined"。然而,有些属性在进行检查时可能会返回 null (typeof null === "object")。 - Rob W
3个回答

7

1. function(){ return{}}是一个闭包,用于将您不想让其它任何地方访问的变量和函数添加“私有性”,但在该函数范围内仍然可以访问。函数周围的括号(function(){})创建了一个函数表达式。它们被使用,因为如果您尝试在()中没有传递任何参数就立即执行function(){}()函数,解析器会抱怨。

2. 如果您想让subA或任何其他扩展对象具有自己的子函数,则确实需要像那样声明,但不一定需要一个闭包。

您可以这样做:

ex.subA = function(x, y){
    return x+y;
}

这可以被称为 var sum = ex.subA(2, 3);

或者你也可以这样做

ex.subA = (function(){

    return {
        add: function(x, y){
            return x+y;
        },
        multiply: function(x, y){
            return x*y;
        }
    }
})();

然后调用它:var sum = ex.subA.add(2, 3); var multiplication = ex.subA.multiply(2,3);

有很多方法可以做到这一点。

3. 是的,没错。你可以将私有函数公开。闭包不允许其他任何方式来做到这一点。

4. 如果你想要别名,是的,你可以将其赋值给一个变量。但是,没有必要这样做。按照你所描述的方式运行就可以了。

阅读Essential JavaScript Namespacing Patterns了解javascript命名空间中的一些基础和模式。


subA.js中的第一个if语句与var ex = ex || {};是否有区别?哪个更好?

首先,if语句应该是if(typeof ex == 'undefined')typeof返回一个字符串。没有必要检查ex是否为false。

是的,它们是不同的。如果变量ex已经定义,if语句将不会执行任何变量赋值。因此,if语句更好。

你使用哪种js代码风格标准?

取决于项目的范围,但大多数情况下使用带有辅助函数的深度对象扩展。


感谢您的精彩回复。我有几个后续问题。关于if(typeof ex == 'undefined')语句,我听说一些浏览器将未定义的变量返回为“undefined”,但其他浏览器将其返回为null,这就是为什么它有两个部分的原因。<br>在代码风格标准方面,我更多地谈论函数命名等方面,但我对使用帮助函数进行深度对象扩展很感兴趣。您能详细说明一下吗?这类似于jQuery.extend吗?您认为使用它来添加其他js文件而不是为每个文件使用不同的命名空间会更好吗? - Michael
@Michael 1)我从未遇到过将null分配给未定义的变量的浏览器。但是,我在JavaScript中还是相对较新的。虽然,我认为你已经阅读了有关NULL被视为对象的内容,这是另一回事。如果您能为此提供参考,我会很高兴阅读它。2)是的,这有点像jQuery.extend。我认为这归结于项目的大小。如果您有一个小项目,可以手动添加命名空间,就像您正在做的那样。如果是一个大项目,您需要某种助手来扩展命名空间。 - Shef
我觉得你是对的,我一定把它和其他东西混淆了。 - Michael
然后以与之前相同的方式调用它。- 你描述的方法不可能实现这一点。 - pimvdb
由于我的子函数需要 ex 已经存在(因为它们的一些函数使用 ex 函数),所以我应该使用这个。if(typeof ex == "undefined") { window.console.log("ex.js 需要在 subX 之前被包含");} else { ex.subA = ....} - Michael
@Michael console.log 在 IE <= 8 中不可用(在 9 中未经测试),它会破坏你的代码。最好将其初始化为一个新对象。 - Shef

2
在您的设计中,您将无法访问在该lambda函数中定义的私有变量/函数,因为它仅返回一个对象,或者您想使用new
1.没有()ex是一个函数而不是函数返回的对象。
2.除非您想传递一些参数进行初始化,否则不需要。例如:
ex.my = (function(name) {var my_name = name;})('bar');

3. 我想你指的是这个私有方法。

ex = (function() {
    var foo = 'bar';
    return {
        show: function() {alert(foo);}
    }
})();

在上述情况下,只有 ex 可以访问 foo。
4.不需要,当一切准备就绪时会调用 $(document).ready(),如果您已经加载了 ex.js,则初始化已完成。

它内部的所有内容都将在 DOM 加载后和页面内容加载之前加载


@2 需要传递哪些参数? @3 我该如何访问私有函数? @4 我不明白你的意思。 - Michael

0

针对问题1和3:

在ex.js中使用闭包风格的定义将允许公开这些公共函数和变量。

我的想法是,最好从匿名函数中返回“ex”,并公开我们需要暴露的函数和变量。

对于问题3。在返回的函数中定义和使用的那些(私有)变量仍然可用于该函数,并且可以通过闭包的属性通过公开的函数使用。

如果外部脚本包含在“head”部分或文件顶部,则应在document.ready之前就可以使用ex,并且可以直接使用。

你让我思考:) 我会在深入研究后更新帖子。非常好的问题。 :)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接