如何在 JavaScript 中声明命名空间?

IT技术 javascript namespaces javascript-namespaces
2021-02-06 01:33:40

如何在 JavaScript 中创建命名空间,以便我的对象和函数不会被其他同名对象和函数覆盖?我使用了以下内容:

if (Foo == null || typeof(Foo) != "object") { var Foo = new Object();}

有没有更优雅或更简洁的方法来做到这一点?

6个回答

我使用在 Enterprise jQuery 站点上找到的方法

这是他们的示例,展示了如何声明私有和公共属性和函数。一切都是作为自动执行的匿名函数完成的。

(function( skillet, $, undefined ) {
    //Private Property
    var isHot = true;

    //Public Property
    skillet.ingredient = "Bacon Strips";

    //Public Method
    skillet.fry = function() {
        var oliveOil;

        addItem( "\t\n Butter \n\t" );
        addItem( oliveOil );
        console.log( "Frying " + skillet.ingredient );
    };

    //Private Method
    function addItem( item ) {
        if ( item !== undefined ) {
            console.log( "Adding " + $.trim(item) );
        }
    }
}( window.skillet = window.skillet || {}, jQuery ));

因此,如果您想访问公共成员之一,您只需转到skillet.fry()skillet.ingredients

真正酷的是您现在可以使用完全相同的语法扩展命名空间。

//Adding new Functionality to the skillet
(function( skillet, $, undefined ) {
    //Private Property
    var amountOfGrease = "1 Cup";

    //Public Method
    skillet.toString = function() {
        console.log( skillet.quantity + " " +
                     skillet.ingredient + " & " +
                     amountOfGrease + " of Grease" );
        console.log( isHot ? "Hot" : "Cold" );
    };
}( window.skillet = window.skillet || {}, jQuery ));

第三个undefined论点

第三,undefinedargument 是 value 变量的来源undefined我不确定它今天是否仍然相关,但是在使用旧浏览器/JavaScript 标准(ecmascript 5,javascript < 1.8.5 ~ firefox 4)时,全局范围变量undefined是可写的,因此任何人都可以重写其值。第三个参数(当未传递值时)创建一个名为的变量undefined,其作用域为命名空间/函数。因为在创建命名空间时没有传递任何值,所以它默认为值undefined

+1 对于这个很棒的样本。对于任何感兴趣的人,这个样本是 Elijah Manor 在 Mix 2011 上的精彩演讲的一部分(忽略标题)live.visitmix.com/MIX11/Sessions/Speaker/Elijah-Manor
2021-03-13 01:33:40
@SapphireSun 的好处window.skillet = window.skillet || {}是它允许多个脚本在事先不知道它们将按什么顺序执行时安全地添加到同一个命名空间。如果您希望能够在不破坏代码的情况下任意重新排序包含的脚本,或者如果您希望使用async 属性异步加载脚本并且因此无法保证执行顺序,这会很有帮助参见stackoverflow.com/questions/6439579/...
2021-03-18 01:33:40
@CpILL:不确定是否仍然相关,但第三个undefined参数是 value 变量的来源undefined在使用较旧的浏览器/javascript 标准(ecmascript 5,javascript < 1.8.5 ~ firefox 4)时,全局范围变量undefined是可写的,因此任何人都可以重写其值。添加您未传递的第三个额外参数使其成为 value undefined,因此您正在创建undefined不会被外部源重写的命名空间范围
2021-03-19 01:33:40
这就是今天的IIFE立即调用函数表达式)。感谢您的回答+1!
2021-03-20 01:33:40
从以利亚的文章中,这里是这种方法的利弊,解释。优点:1. 公共和私有属性和方法,2. 不使用繁琐的 OLN,3. 保护未定义 4. 确保 $ 引用 jQuery,5. 命名空间可以跨文件,缺点:比 OLN 更难理解
2021-03-28 01:33:40

我喜欢这个:

var yourNamespace = {

    foo: function() {
    },

    bar: function() {
    }
};

...

yourNamespace.foo();
这不会为您的代码创建一个闭包——它使调用其他函数变得乏味,因为它们总是看起来像: yourNamespace.bar(); 我做了一个开源项目来解决这个设计问题:github.com/mckoss/namespace
2021-03-11 01:33:40
annakata:“重要的一点是要虔诚地扩展不超过一个根变量。” - 为什么会这样?
2021-03-11 01:33:40
@alex - 为什么应该有一个浅层对象结构?
2021-03-20 01:33:40
重要的一点是对扩展不超过一个根变量的虔诚。一切都必须由此而生。
2021-03-25 01:33:40
@Ryan 我的意思是一切都应该在MyApp,例如MyApp.Views.Profile = {}而不是MyApp.users = {}MyViews.Profile = {}不一定只有两个级别的深度。
2021-04-06 01:33:40

另一种方法,我认为它比对象字面形式的限制少一点,是这样的:

var ns = new function() {

    var internalFunction = function() {

    };

    this.publicFunction = function() {

    };
};

以上与module模式非常相似无论您喜欢与否,它都允许您将所有函数公开为公共,同时避免对象字面量的刚性结构。

我喜欢这种方法,因为它允许私有函数、变量和伪常量(即 var API_KEY = 12345;)。
2021-03-16 01:33:40
我比投票更高的逗号分隔对象容器更喜欢这个。相比之下,我也没有看到任何缺点。我错过了什么吗?
2021-03-19 01:33:40
@John Kraft,这是因为new关键字前面的function关键字。基本上,它所做的是声明一个匿名函数(作为一个函数,它也是一个构造函数),然后它立即使用new. 因此,存储在其中的最终值ns是该匿名构造函数的(唯一)实例。希望这是有道理的。
2021-03-26 01:33:40
JS 新手在这里...为什么我不必输入ns().publicFunction(),即...ns.publicFunction()有效。
2021-03-31 01:33:40
1. OLN 和module模式的区别。2.我不/总是/喜欢OLN,因为您必须记住不要放置最后一个尾随逗号,并且您的所有属性都必须用一个值(如空值或未定义)进行初始化。此外,如果您需要成员函数的闭包,则每个方法都需要小型函数工厂。另一件事是您必须将所有控制结构包含在函数中,而上述形式并未强加这一点。这并不是说我不使用 OLN,只是有时我不喜欢它。
2021-04-07 01:33:40

有没有更优雅或更简洁的方法来做到这一点?

是的。例如:

var your_namespace = your_namespace || {};

那么你可以拥有

var your_namespace = your_namespace || {};
your_namespace.Foo = {toAlert:'test'};
your_namespace.Bar = function(arg) 
{
    alert(arg);
};
with(your_namespace)
{
   Bar(Foo.toAlert);
}
@Palo 你能解释一下为什么应该是这样吗? var your_namespace = your_namespace = your_namespace || {}
2021-03-10 01:33:40
您可以在不同的 js 文件中扩展 your_namespace 对象。使用 var your_namespace = {} 时,您不能这样做,因为该对象将被每个文件覆盖
2021-03-19 01:33:40
然而MDN 不鼓励使用with?
2021-03-20 01:33:40
这给了我在 IE7 中的错误。var your_namespace = (typeof your_namespace == "undefined" || !your_namespace ) ? {}:你的名字空间;效果更好。
2021-03-24 01:33:40
它应该是 var your_namespace = your_namespace = your_namespace || {} 适用于所有浏览器;)
2021-04-03 01:33:40

我通常在闭包中构建它:

var MYNS = MYNS || {};

MYNS.subns = (function() {

    function privateMethod() {
        // Do private stuff, or build internal.
        return "Message";
    }

    return {
        someProperty: 'prop value',
        publicMethod: function() {
            return privateMethod() + " stuff";
        }
    };
})();

自从写这篇文章以来,多年来我的风格发生了微妙的变化,现在我发现自己写了这样的闭包:

var MYNS = MYNS || {};

MYNS.subns = (function() {
    var internalState = "Message";

    var privateMethod = function() {
        // Do private stuff, or build internal.
        return internalState;
    };
    var publicMethod = function() {
        return privateMethod() + " stuff";
    };

    return {
        someProperty: 'prop value',
        publicMethod: publicMethod
    };
})();

通过这种方式,我发现公共 API 和实现更容易理解。将 return 语句视为实现的公共接口。

一个很好的点,应该是开发人员意图的练习。您需要考虑当它确实存在时该怎么做,替换它,出错,使用现有或版本检查并有条件地替换。我遇到过需要每种变体的不同情况。在大多数情况下,您可能会将其视为低风险的边缘情况,更换可能是有益的,请考虑尝试劫持 NS 的流氓module。
2021-03-11 01:33:40
你不应该检查MYNS.subns = MYNS.subns || {}吗??
2021-03-15 01:33:40
优化提示:whilevar foo = functionfunction foo是相似的,是私有的;由于 JavaScript 的动态类型特性,后者快,因为它跳过了大多数解释器管道中的一些指令。使用var foo,类型系统必须被调用以找出被分配给所述 varfunction foo的类型,而使用,类型系统自动知道它是一个函数,因此会跳过几个函数调用,这意味着更少的 CPU 指令调用,例如jmppushqpopq等,这意味着更短的 CPU 管道。
2021-03-25 01:33:40
@brett oop。你是对的。我在想一种不同的脚本语言。虽然我仍然坚持function foo语法更具可读性。我仍然喜欢我的版本。
2021-03-25 01:33:40
如果有人在第 412 页的“Speaking Javascript”一书中有这种方法的解释,则在“Quick and Dirty Modules”标题下。
2021-03-28 01:33:40