Классы JavaScript и область переменных

Я относительно новичок в 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" ). Доступ к нему можно получить изнутри clazz как: 'a'.

b - общедоступная переменная, специфичная для экземпляра. Его можно получить изнутри clazz как "this.b" и извне clazz как "myClazz.b".

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

d - это переменная public, статическая/классная. Доступ к нему можно получить из любого места: clazz.prototype.d или myClazz.prototype.d.

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

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

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

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

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

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

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

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

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

Ответ 1

Вы правы для a и b:

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

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

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

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

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

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

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

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

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

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

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

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

  function privateMethod () {
    // ...
  }

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

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

Дополнительная информация:

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

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

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

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

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

Ответ 2

ОК, переходим к следующему:

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

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

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

  • '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';
    
  • Статические члены класса определяются с помощью:

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

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

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

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

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

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

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