为什么将 javascript 命名空间作为函数?

Why base a javascript namespace as a function?

我正在阅读一个必须保持匿名的库的源代码,我看到它使用一个空函数来设置命名空间。它看起来类似于对象文字表示法 (OLN),只是基数是一个函数。

这是一个声明示例。

/**
 * Base namespace for FOO library
 * @name FOO
 * @namespace
 */
function FOO(){}

FOO.bar = 'bar const..';
FOO.fooFunc = function () { /* code */ };
FOO.Bar = function () { /* some constructor */ };
FOO.Bar.prototype.baz = function () { /* A prototype method on FOO.Bar */ };
...

如您所见,FOO 命名空间是一个空函数。将命名空间声明为空函数有什么意义吗?这是对 OLN 模式的误用吗?看起来它可能是工厂模式的开始。命名空间上没有原型方法(例如 FOO.prototype.bar = ...)。调用 FOO() 显然什么都不做。有人认识这个图案吗?

我通常通过以下方式看到此操作:

var FOO = FOO || {};

这样全局就不会被覆盖。

为什么声明一个空函数?

这样作者就可以向 FOO 添加方法。这只是一种实现方式,因为在 JavaScript 中,包括函数在内的大部分内容都是对象。

请查看此内容以获得更好的解释:How is almost everything in Javascript an object?

命名函数 hoisted - 有效地移动到其封闭范围的顶部。使用命名函数可以允许在声明命名空间之前进行赋值:

FOO.bar = "bar";
function FOO() {}
console.log(FOO.bar); // bar

与对象文字(或未命名函数)相比:

FOO.bar = "bar";
var FOO = {};
console.log(FOO.bar); // undefined

不太可能有人会计划将成员分配给这样的命名空间,但它可能会发生。

我能想到的唯一其他优点是函数可以有一个固有的名称,这可能对调试有用。

例如,如果命名空间成员有 namespace 属性(他们可能没有):

function FOO(){}
FOO.bar = { namespace: FOO };
console.log(FOO.bar.namespace); // function FOO(){}

相比于:

var FOO = {};
FOO.bar = { namespace: FOO };
console.log(FOO.bar.namespace); // Object {bar: Object}

纯粹的推测:也有可能某些名称空间可以使用这样的函数进行初始化。这可能是一个命名空间的例子,它不需要任何初始化,但选择使用一个函数来保持一致性。