Классы 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".