构造函数 - 在简单的命名空间中 - Javascript

3
我想在命名空间中定义一个函数构造器。到目前为止,我定义构造器的方式是一个简单的没有命名空间的构造函数,结合原型继承。
代码看起来像这样:
 function mySuperObject() {
    var self = this;
    self.p1 = "";
    self.p2 = "jkejie";
    // and others
    }
 mySuperObject.prototype.func1 = function(){...}
 // and others

介绍命名空间:

在阅读了许多文章之后,我决定用一种非常简单的方式来定义命名空间,可能是最简单的方式。基本上就是定义一个指向对象字面量的变量,并且内容是对象(代码段中的“mySuperObject”)。构造函数如下:mySuperObjectInNS。

对象的代码:

var MYNAMESPACE = {

    //some variable outside the object
    file : "ConstructorInNamespace_obj.js: ",

    //Defining contructor function inside a namespace
    mySuperObjectInNS : function(propOne, propTwo){

        var self = this;
        self.objectName = "mySuperObject";
        self.propertyOne = propOne;
        self.propertyTwo = propTwo;

        self.doSomething = function(){
            console.log(file + " doSomething called - function of object");
        };

        ///many more functions and attributes
    }
}

MYNAMESPACE.mySuperObjectInNS.prototype.specialFunction = function(){
    console.log(file + " specialFunction called - prototypical inheritance defined in file of object, outside of namespace");
};

///many more functions and attributes

在另一个文件中,可以按照以下方式实例化对象:
...
var objOne = new MYNAMESPACE.mySuperObjectInNS("param11", "40");
//following line works just fine
objOne.doSomething();
 ....

问题:

  • 在我看来,这一切都是关于定义一个对象字面量的,但当我尝试定义该对象的“私有”属性时,我最终会遇到麻烦。这是正确的吗?
  • mySuperObjectInNS仍然是一个构造函数吗?(对我来说它似乎是其他东西,即使我可以从它实例化对象。
  • 这是一种非常糟糕的命名空间方式还是还算可以接受的?
1个回答

4
我认为这一切都是关于定义对象字面量,而我在试图定义该对象的“私有”属性时会遇到麻烦。这正确吗?
“私有属性”与使用对象作为命名空间无关。事实上,最初回答这个问题时,我将其解释为“私有函数”,因为那才是相关的。
在JavaScript中,有很多方法可以实现私有和半私有属性,但它们涉及如何创建构造函数以及构造函数提供对象的方法,而不是如何公开构造函数。 “命名空间”对象是关于如何公开构造函数的。
创建“私有”属性的一种常见模式是,在构造函数内部定义需要访问它们的方法,并将“属性”作为构造函数内部的局部变量(因此它们实际上并不是属性),例如:
function SuperObject() {
    var privateInformation;

    this.method = function() {
        // This can access `privateInformation`, which is completely
        // hidden from outside the constructor
    };
}

如果您在“命名空间”模式内或独立使用都没有关系。

另一方面,私有函数会影响模式。我将在下面展示两者。

一种相当常见的变体是使用函数创建对象,这也为您提供了创建私有函数的机会:

var TheNamespace = function() {
    function privateFunction() {
    }

    function SuperObject() {
        var privateInformation;

        this.method = function() {
            // This can access `privateInformation`, which is completely
            // hidden from outside the constructor
        };
    }

    SuperObject.prototype.otherMethod = function() {
        // Can't access `privateInformation`, but has the advantage
        // that the function is shared between instances
    };

    return {
        SuperObject: SuperObject
    };
}();

// usage
var s = new TheNamespace.SuperObject();

mySuperObjectInNS仍然是一个构造函数吗?(对我来说,它似乎是其他东西,即使我可以从中实例化对象。)

是的。构造函数是任何期望您使用 new 的函数。

这是一种非常糟糕的命名空间方式还是可以接受的呢?

使用对象作为伪命名空间是常见的做法。您还可以考虑使用各种异步模块定义(AMD)技术,这在很大程度上使得“命名空间”对象变得不再必要。


关于您的评论:

您定义了一个自执行函数...返回一个对象?

这不是一个 自执行 函数,而是一个 内联 调用函数,但是是一个返回对象的函数。

(如果是的话,我认为漏了括号)

不需要额外的括号,因为其他地方使用外部括号的唯一原因是告诉解析器单词 function 开始的是表达式而不是声明。在上面的情况下,我们已经在赋值的右侧,因此当遇到 function 时不存在歧义。

由于您提出了这种方式,这是定义 ns 的更好方式吗?

"更好" 是一个主观的术语。它为您提供了可以定义私有函数的范围,这是您所询问的。

而我经常看到的选项也包括: var = {} | someNSName; 这是什么意思?

如果您有多个文件将添加东西到"命名空间"(这是常见的),那么您经常会在每个文件中看到以下内容:
var TheNamespace = TheNamespace || {};

这个操作会声明变量,如果该变量之前未被声明,则会将其赋值为空对象;如果它已经有一个空对象,则不进行任何操作。在第一个加载的文件中,会发生以下操作:
  1. 处理var并创建一个新的变量TheNamespace,其值为undefined

  2. 处理TheNameSpace = TheNameSpace || {}赋值:由于undefined是假值,奇妙而强大的||运算符 的结果是新的{},它被赋值给TheNamespace

下一个文件加载时,会发生以下操作:
  1. var 是一个空操作,因为变量已经存在。

  2. 处理 TheNameSpace = TheNameSpace || {} 赋值:由于 TheNamespace 有非 null 的对象引用,它是真值,并且神奇的强大的 || 运算符导致引用指向 TheNamespace 所引用的对象。

也就是说,它根本没有任何影响。

这样做的目的是让您可以以任何顺序加载文件,或仅加载单个文件。

下面是一个示例:

thingy.js:

var TheNamespace = TheNamespace || {};
TheNamespace.Nifty = function() {
    function privateFunction() {
    }

    function Nifty() {
        var privateInformation;

        this.method = function() {
            // Can access `privateInformation` here
        };
    }

    Nifty.prototype.otherMethod = function() {
        // ...
    };

    return Nifty;
}();

thingy.js:

var TheNamespace = TheNamespace || {};
TheNamespace.Thingy = function() {
    function privateFunction() {
    }

    function Thingy() {
        var privateInformation;

        this.method = function() {
            // Can access `privateInformation` here
        };
    }

    Thingy.prototype.otherMethod = function() {
        // ...
    };

    return Thingy;
}();

基本模式有很多变化,尤其是如果一个文件可能向TheNamespace添加多个内容。下面是一个相当简洁支持这样做的例子:

var TheNamespace = function(exports) {
    function privateFunction() {
    }

    function Nifty() {
        var privateInformation;

        this.method = function() {
            // Can access `privateInformation` here
        };
    }

    Nifty.prototype.otherMethod = function() {
        // ...
    };

    exports.Nifty = Nifty;

    function Thingy() {
        var privateInformation;

        this.method = function() {
            // Can access `privateInformation` here
        };
    }

    Thingy.prototype.otherMethod = function() {
        // ...
    };

    exports.Thingy = Thingy;
}(TheNamespace || {});

你好,Crowder。感谢你的回复,但我有一个问题:你定义了一个自调用函数(如果是这样,我认为括号丢失了),它返回一个对象?由于你提出了这种方式,是否更好地定义了ns?因为这是一种常见的做法,所以我想我可以使用它。而我经常看到的选项是:var = {} | someNSName; 这是怎么回事?(或者我应该发一个额外的问题...?) - Meru
@Meru:我已经添加了答案以回答那些后续问题。 - T.J. Crowder
1
再次见到你们。如何使用函数表达式来定义函数,例如:var mysuperFunction = function () {....}? - Meru
@Meru:关于什么? - T.J. Crowder
1
@Meru:在上述情况下,无论您使用函数表达式(var mySuperFunction = function() { ... })还是函数声明(function mySuperFunction() { ... }),都没有关系。 - T.J. Crowder
显示剩余3条评论

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