Пространство имен, ООП JS, я делаю это правильно? - PullRequest
1 голос
/ 18 сентября 2010

Моя проблема с 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 ]

4 голосов
/ 18 сентября 2010

Кроме пространств имен, мне не совсем понятно, что вы пытаетесь сделать, но я включил своего рода обзор кода под разделителем ниже.Сначала более высокоуровневые комментарии.

Здесь есть несколько проблем.Во-первых, вы почти никогда не хотите писать new function() { }.Это очень продвинутый метод, который легко ошибиться (и очень легко для любого, кто занимается обслуживанием кода, неправильно его понять).Ниже приведен пример другого, менее запутанного способа получения того же эффекта (плюс некоторые другие преимущества).

Вот пример модуля с пространством имен, предоставляющего два "класса", Cat и Lion (Я сделал их изначально ограниченными, потому что это обычное соглашение: начальные заглавные буквы для функций конструктора и начальные строчные буквы для неструктурных функций, просто для облегчения чтения кода):

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 что угодно, что угодно - pubs, p, что угодно. Это эквивалент this во внешнем слое вашей new function() { } функции, но менее запутанно.)

Но просто заменить прототип на Lion немного проще.Когда вы начинаете переходить на подклассы, есть несколько других вещей, на которые вы хотите посмотреть. Вот запись в блоге , в которой подробно описаны достаточно полные способы построения классов, включая создание подклассов, вызов функций суперкласса и т. Д.

С точки зрения поиска чего-либо по строке, вы можете сделать это с помощью скобокобозначение любого объекта:

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 голос
/ 18 сентября 2010

Вы, по сути, сделали все, кроме 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 пример 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 пример


Я использовал функциональное наследование выше. Я считаю, что с ним проще работать, и он хорошо использует бесклассовую природу объектно-ориентированной персоны Javascript.

В качестве тестового вывода я вернулся непосредственно из lion ... что вы обычно не делаете, просто чтобы показать, что изменение Simba не изменит lion. Вы можете сказать, что диета lion имеет приоритет перед диетой cat, как вы и хотели.

Хитрость заключается в том, чтобы упаковать переменные и методы protected и public в возвращаемые объекты, и не забывайте, что вы также можете создавать методы в своих кошках.

0 голосов
/ 18 сентября 2010

Вы можете использовать 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);

Я отредактировал код, чтобы использовать менее подверженную ошибкам форму инкапсуляции. Эта статья мне очень помогла: Открытое и частное в JavaScript .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...