【问题标题】:Namespacing, OOP JS, Am I doing this right?命名空间,OOP JS,我这样做对吗?
【发布时间】:2011-04-14 03:39:27
【问题描述】:

我的问题是 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);

注意:来源是从各个地方采样的

【问题讨论】:

标签: javascript oop namespaces


【解决方案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】:

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

    这里有几个问题。首先,你几乎从不想写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/0)。不,没用。
    • @Matrym:哈哈!!不用担心,很高兴有帮助。
    【解决方案3】:

    您可以使用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.

    【讨论】:

    • 或者去 Crockford 的更权威的作品:javascript.crockford.com/private.html
    • @T.J.克劳德:是的,那个也是,但是那个更抽象一点。达斯汀迪亚兹的文章向我介绍了这个概念,直到我理解它,然后克罗克福德的文章完成了我的理解。
    • 是的,Crockford 适合密集阅读。不过,如果达斯汀迪亚兹引用了他的消息来源会很好,因为他几乎肯定读过克罗克福德或读过克罗克福德的人。 :-)
    猜你喜欢
    • 1970-01-01
    • 2012-08-13
    • 2023-03-19
    • 1970-01-01
    • 1970-01-01
    • 2015-01-13
    • 2015-06-09
    • 2014-06-28
    • 1970-01-01
    相关资源
    最近更新 更多