Namespacing,OOP JS,我这样做对吗?

时间:2010-09-18 17:36:48

标签: javascript oop namespaces

我的问题在于objInfo()。如何通过传入变量返回对象?我正在尝试命名我的代码并使用私有/公共变量。

奖金问:你如何改进代码?

// Namespace all my code
var bab = new function() {

    // Declare cat object
    function cat()
    {
      this.eyes = 2;
      this.legs = 4;
      this.diet = 'carnivore';

      return true;
    }

    // Declare lion object
    function lion()
    {
      this.mane = true;
      this.origin = 'Africa';
      this.diet = 'people'; // has priority over cat's diet

      return true;
    }

    // Make lion a subclass of cat
    lion.prototype = new cat();

    // Create an instance of class lion
    var simba = new lion();

    // Share diet publicly
    this.objInfo = function(name) {
        return name; // simba works, name doesn't
    };

};

alert(bab.objInfo('simba').diet);

注意:来自各个地方的来源

3 个答案:

答案 0 :(得分:4)

除了命名空间之外,我不清楚你要做什么,但我在下面的分隔符下包含了各种代码审查。首先是更高级别的评论。

这里有几个问题。首先,你几乎从不想要写new function() { }。这是一种非常先进的技术,容易出错(并且很容易让对代码进行维护的人误解)。下面是一个另一种不那么令人困惑的方法来获得相同的效果(以及其他一些好处)。

这是一个命名空间模块的示例,它提供了两个“类”,CatLion(我最初限制它们,因为这是通常的惯例:构造函数的初始上限和初始下限关于非构造函数的情况,只是为了便于阅读代码):

var Animals = (function() {
    var publics = {};

    // A Cat
    publics.Cat = Cat;
    function Cat() {
        this.eyes = 2;
        this.legs = 4;
        this.diet = 'carnivore';
    }

    // A Lion
    publics.Lion = Lion;
    function Lion() {
        this.mane = true;
        this.origin = 'Africa';
        this.diet = 'people'; // has priority over cat's diet
    }
    Lion.prototype = new Cat();

    // Return our public symbols
    return publics;
})();

// Usage
var l = new Animals.Lion();
alert(l.eyes); // alerts "2" (inherited from Cat)
alert(l.diet); // alerts "people" (overridden by Lion)

(当然,您可以拨打publics您想要的任何内容 - pubsp,无论如何。这相当于您最外层的this new function() { }功能,但不那么令人困惑。)

但只是替换Lion上的原型有点过分了。当你开始进入子类化时,还有其他一些你想要做的事情。 Here's a blog post详细说明了构建类的相当完整的方法,包括子类化,调用超类函数等。

在按字符串查找内容方面,您可以在任何对象上使用括号表示法来执行此操作:

var obj = {};
obj.foo = 42;
alert(obj["foo"]); // alerts "42" by retrieving the property "foo" from `obj`
var x = "f" + "o" + "o";
alert(obj[x]);     // alerts "42" by retrieving the property "foo" from `obj`

代码审查如下。


以下是代码审核:

// Namespace all my code
// [TJC] Use the (function() { ... })(); mechanism described above rather than
// `new function() { ... }`, which is fairly confusing to the reader and troublesome
// to use inside inner functions (see below)
var bab = new function() {

    // Declare cat object
    // [TJC] Convention is to use initial caps for constructor functions,
    // e.g. "Cat" not "cat"
    function cat()
    {
      this.eyes = 2;
      this.legs = 4;
      this.diet = 'carnivore';

      // [TJC] Don't return anything out of constructor functions
      return true;
    }

    // Declare lion object
    // [TJC] "Lion" rather than "lion" would be more conventional
    function lion()
    {
      this.mane = true;
      this.origin = 'Africa';
      this.diet = 'people'; // has priority over cat's diet

      // [TJC] Don't return anything out of constructor functions
      return true;
    }

    // Make lion a subclass of cat
    // [TJC] There are several other things you want to consider in
    // addition to replacing the prototype
    lion.prototype = new cat();

    // Create an instance of class lion
    // [TJC] From your usage below, it looks like you
    // want to be able to look up "simba" using a string
    // later. So use the below rather than this commented-out
    // line:
    //var simba = new lion();
    var instances = {};           // [TJC]
    instances.simba = new lion(); // [TJC]

    // Share diet publicly
    // [TJC] You don't need a function for this at all, just
    // expose "instances" directly. But if you want it:
    this.objInfo = function(name) {
            // [TJC] To look up something by name using a string,
            // use brackets:
        //return name; // simba works, name doesn't
            return instances[name]; // [TJC]
    };

};

alert(bab.objInfo('simba').diet);

答案 1 :(得分:1)

您基本上已经使objInfo()中的bab已经过时了,因为 objInfo()只会准确地返回传递给它的内容。

在您的具体情况下,objInfo("simba")无效,因为objInfo()只返回字符串"simba"

    ...
    // Share diet publicly
    this.objInfo = function(name) { // <-- If name == "simba"
        return name; // <-- This will return "simba" not the Object simba!!!
    };

};

alert(bab.objInfo('simba').diet);​ // This will check for the diet property of
                                  //   the string "simba". So it won't work.

然而,正如我之前提到的,存在更大的问题。 objInfo()只是简单地返回传递给它的内容!

试试这些例子:

alert(bab.objInfo('simba'));            // This will alert "simba"
alert(bab.objInfo('noodles'));          // This will alert "noodles"
alert(bab.objInfo(window).innerWidth);  // This will give you the innerWidth of

jsFiddle example of alert(bab.objInfo(window).innerWidth);


您基本上“短路”了整个bab对象。只有objInfo方法“做”任何事情。


我就是这样做的:

// Namespace all my code
var bab = new function() {    
    var cat = function() // Declare cat object
    {
      var protected = {}; // Protected vars & methods
      protected.eyes = 2;
      protected.legs = 4;
      protected.diet = 'carnivore';
      return protected; // Pass protected to descendants
    }
    var lion = function()
    {     
      var protected = cat();  // Make lion a subclass of cat        
      var public = {}; // Public vars & methods
      public.legs = protected.legs; // Make 1 protected var public
      public.mane = true;
      public.origin = 'Africa';
      public.diet = 'people'; // has priority over cat's diet
      return public; // Make public vars available
    }    
    var simba = lion();     // Create an instance of class lion
    simba.diet = "Asparagus"; // Change simba, but not lion
    // Get property of choice
    this.objInfo = function(property) {
        return ("Simba: " + simba[property] +
                " - Lion (this is usually private. Shown for testing.): " +
                lion()[property]);
    };
};
alert(bab.objInfo("diet"));

jsFiddle example


我在上面使用了功能继承。我觉得使用它更简单,它充分利用了Javascript的面向对象角色的无类别特性。

作为测试输出,我直接从lion返回...您通常不会这样做,只是为了表明更改Simba不会更改lion。你可以说lion的饮食优先于cat的饮食,就像你想要的那样。

诀窍是将你的protectedpublic变量和方法打包在返回的对象中,不要忘记你也可以在你的猫科动物中创建方法。

答案 2 :(得分:0)

您可以使用eval,但我不愿意推荐。

您可以通过在阵列中“注册”您的狮子来改进脚本。

// Namespace all my code
var bab = (function() {
        // Declare cat object
        function cat() {
            this.eyes = 2;
            this.legs = 4;
            this.diet = 'carnivore';

            return true;
        }

        // Declare lion object
        function lion() {
            this.mane = true;
            this.origin = 'Africa';
            this.diet = 'people'; // has priority over cat's diet

            return true;
        }

        // Make lion a subclass of cat
        lion.prototype = new cat();

        // Create an instance of class lion
//      var simba = new lion();
        var lions = {}; // Create a "lions" object to collect all of the lion instances
        lions["simba"] = new lion();

    return {
        // Share diet publicly
        objInfo: function(name) {
            return lions[name];
        };
    }
})();

alert(bab.objInfo('simba').diet);

我编写了代码以使用不易出错的封装形式。这篇文章给了我很多帮助:Public and Private in JavaScript