Классы JavaScript и область действия переменных - PullRequest
11 голосов
/ 01 декабря 2009

Я относительно новичок в JS, и у меня возникают проблемы с правильной имитацией принципов ООП.

Полагаю, у меня есть два вопроса. Вопрос: Первый касается множества способов объявления переменных.

Скажи, что у меня есть класс:

function clazz(a)
{
    this.b = 2;
    var c = 3;
    this.prototype.d = 4; // or clazz.prototype.d = 4?
}

var myClazz = new clazz(1); 

Прав ли я в следующих оценках:

a - это закрытая переменная, которая специфична для конкретного экземпляра (то есть разные экземпляры clazz будут иметь уникальные и независимые переменные 'a'). Доступ к нему изнутри можно получить как: «a».

b является публичной переменной, которая зависит от конкретного экземпляра. Доступ к нему можно получить изнутри clazz как «this.b», а снаружи - как «myClazz.b».

c - это закрытая переменная, которая является статической или специфичной для класса (то есть разные экземпляры clazz будут использовать одну и ту же переменную 'c'). К нему можно получить доступ из любого экземпляра clazz как «c», а изменения в экземпляре clazz отражаются во всех экземплярах clazz.

d является публичной переменной, которая является статической / специфичной для класса. Доступ к нему можно получить из любого места через «clazz.prototype.d» или «myClazz.prototype.d».

Общая проблема с моим пониманием схемы переменных заключается в том, что нет способа объявить частную переменную, которая НЕ является статической (то есть уникальной версией для каждого экземпляра класса).

Второй вопрос касается различных типов объявлений классов.

Я использовал:

var MySingleton = new function() {...};

для создания синглетонов. Это правильно? Я также не уверен относительно влияния ключевого слова "new" в этой ситуации, а также добавление скобок функции () в конец объявления следующим образом:

var MySingleton = new function() {...}();

Я использовал этот шаблон для объявления класса, а затем для создания экземпляров этого класса:

function myClass() {...};
var classA = new myClass();
var classB = new myClass();

Это правильный метод?

Ответы [ 2 ]

19 голосов
/ 01 декабря 2009

Вы подходите для a и b:

a - это аргумент, доступный только в рамках функции конструктора .

b является общедоступной переменной экземпляра, доступной во всех экземплярах, созданных с помощью этой функции конструктора.

c является закрытой переменной, доступной только внутри функции конструктора.

Объявление d недопустимо, поскольку объект prototype предназначен для использования только в функциях конструктора , например Clazz.prototype.d = 3;, если вы сделаете это так, переменная будет разделена , но вы можете присвоить значение конкретному экземпляру, и значением по умолчанию будет shadowed (через цепочку прототипов).

Для «приватных переменных» вы можете использовать способ объявления c, например:

function Clazz(){
    var c = 3; // private variable

    this.privilegedMethod = function () {
      alert(c);
    };
}

Привилегированные методы общедоступны, но они могут обращаться к "закрытым" переменным, объявленным внутри функции конструктора.

Для создания синглетонов, возможно, проще всего использовать литерал объекта, например:

var myInstance = {
  method1: function () {
    // ...
  },
  method2: function () {
    // ...
  }
};

А если вы хотите, чтобы в вашем экземпляре синглтона были приватные участники, вы можете:

var myInstance = (function() {
  var privateVar = '';

  function privateMethod () {
    // ...
  }

  return { // public interface
    publicMethod1: function () {
      // all private members are accesible here
    },
    publicMethod2: function () {
    }
  };
})();

Это был назван шаблон модуля, он в основном позволяет инкапсулировать приватные элементы в объекте, используя преимущества замыканий .

Подробнее:

Редактировать: О синтаксисе, который вы публикуете:

var mySingleton = new (function() {
  // ...
})();

Используя оператор new, вы объявляете и используете в один шаг" анонимную функцию-конструктор ", которая будет генерировать новый экземпляр объекта, он действителен, но Лично я предпочел бы шаблонный подход «модуль», чтобы создать свой собственный экземпляр объекта (и избегать new).

Также, читая new function () {}, я думаю, что это не совсем интуитивно и может создать путаницу, если вы не очень хорошо понимаете, как работает оператор new.

О скобках, они необязательны, оператор new вызовет конструктор функции без параметров, если вы не добавите их ( см. ECMA-262 , 11.2.2 ).

3 голосов
/ 01 декабря 2009

ОК, давайте рассмотрим это:

  1. 'a' - аргумент, передаваемый конструктору вашего класса. Он будет существовать только на время вызова конструктора. Это означает, что вы, вероятно, должны где-то хранить его значение.

  2. 'b' является открытым экземпляром. Это зависит от конкретного экземпляра (хотя, поскольку вы присваиваете значение в конструкторе, изначально все экземпляры будут иметь одинаковое значение для 'b').

  3. 'c' является участником частного экземпляра. Однако он будет доступен только внутри вашего конструктора, поскольку он определен только в этой области. Если вы не ссылаетесь на него из замыкания внутри функции конструктора, его судьба будет аналогична той, что указана выше в «а».

  4. 'd' является открытым экземпляром. Каждый экземпляр вашего класса изначально будет иметь член 'd' со значением 4. Однако обратите внимание, что при назначении объекта ссылочного типа члену-прототипу вашего класса (например, «d») каждый член экземпляра «d» будет ссылаться на один и тот же объект. Пример:

    MyClass.prototype.d = { prop1: 'val1', prop2: 'val2' };        
    var a = new MyClass();
    var b = new MyClass();        
    a.d.prop1 = 'foo'; // is the same as: b.d.prop1 = 'foo';
    
  5. Статические члены класса определяются с помощью:

    function MyClass()
    {
      // ...
    }    
    MyClass.staticMemeber = 'I am a static member';
    

    Вероятно, вам не следует рассматривать MyClass.prototype как место для хранения ваших статических членов / методов. Все, что назначено прототипу класса, в свою очередь является членом каждого из его экземпляров.

  6. Когда () присоединяются к определению функции (сразу после кадра), функция выполняется. Это значит:

    var myFunc = function() { alert('blah'); }();
    

    приведет к не более чем вызову метода. Следующий код:

     var MySingleton = new function() {...}();
    

    будет означать «использовать возвращаемое значение из функции () в качестве конструктора для MySingleton».

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