ООП в Java Script (3): Свойства и методы класса

Свойства и методы класса (члены класса) могут быть открытыми (public), закрытыми (private), привилегированными (privileged) и статическими (static).

Открытые (public) члены

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

Открытые свойства задаются с помощью ключевого слова .this внутри функции-конструктора:

var Class = function(p){
this.p = p;
}

var o = new Class('karaboz');
alert(o.p); // выводит 'karaboz'

o.p = 'mertas';
alert(o.p); // выводит 'mertas'

Открытые методы задаются с помощью .prototype функции-конструтора:

Class.prototype.method = function(){
alert('my name is .method');
}
obj.method(); // выводит 'my name is .method'

obj.method = function(){
alert('my name is .method, but I am new one!');
}
obj.method(); // выводит 'my name is .method, but I am new one!'

Присваивая объекту obj метод .method, мы не изменяем одноименный метод в .prototype функции-конструтора, а лишь закрываем его от интерпретатора, создавая в нашем объекте новое свойство с тем же именем. Т.е. все вновь создаваемые объекты будут по-прежнему обладать стандартным методом из .prototype.

Мы можем позволить объекту вновь видеть и пользоваться методом из .prototype. Для этого нужно просто удалить свойство .method самого объекта:

delete o.method;
o.method(); // вновь выводит 'my name is .method'

Свойства и методы, заданные через .prototype функции-конструктора, не копируются во вновь создаваемые объекты. Все объекты данного класса пользуются ссылкой на одни и те же свойства и методы. Одновременно, открытые члены мы можем определять в любой точке программы, в том числе даже и после создания объекта (экземпляра) класса.

Закрытые (private) члены

Закрытые свойства и методы недоступны напрямую извне объекта. Они описываются прямо в функции-конструкторе класса и создаются при инициализации объекта. Такими свойствами обладают переменные, переданные в качестве параметров в функцию-конструтор, переменные, объявленные с помощью ключегого слова var, а также функции, объявленные как локальные внутри функции-конструтора.

var Class = function(p){
var secret = p;
var count = 3;

var counter = function(){
count –;
if(count > 0){
return true;
} else {
return false;
}
}
}

Свойствa secret, count и метод counter создаются в объекте при его инициализации. Они называются закрытыми, потому что к ним нет доступа как у кода извне объекта, так и у открытых методов самого объекта. Чтобы понять, как можно использовать эти закрытые свойства, нужно обратиться к привилегированным методам.

Привилегированные (privileged) методы

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

Привилегированный метод определяется в конструкторе с помощью ключевого слова this:

var Class = function(p){
var secret = p;
var count = 3;

var counter = function(){
if(count > 0){
count –;
return true;
} else {
return false;
}
}

this.tellSecret = function(){
if(counter()){
return secret;
} else {
return null;
}
}
}
var o = new Class('12345');


alert(o.tellSecret()); // выводит '12345'
alert(o.tellSecret()); // выводит '12345'
alert(o.tellSecret()); // выводит '12345'
alert(o.tellSecret()); // выводит null

// безуспешно пытаемся переписать закрытый метод counter,
// a на самом деле, просто создаем новый одноименный открытый метод
o.counter = function(){
return true;
}
alert(o.tellSecret()); // все равно выводит null

.tellSecret и есть привилегированный метод. Он возвращает закрытое свойство secret при первых трех вызовах, а при всех последующих начинает возвращать null. Каждый раз .tellSecret вызывает закрытый метод counter, который сам обладает доступом к закрытым свойствам объекта. Любой код имеет доступ к методу .tellSecret, но это не дает прямого доступа к закрытым членам объекта.

В отличие от открытых методов, создаваемых через .prototype, копия привилегированного метода создается в каждом создаваемом объекте, что естественно влечет за собой больший расход памяти. Закрытые и привилегированные члены создаются только в момент инициализации объекта и позже уже не могут быть изменены.

Статические (static) члены

Статические свойства и методы - это свойства и методы, привязанные к самой функции-конструтору (к самому классу). Поэтому их еще называют свойствами и методами класса. Они доступны любому коду как внутри, так и за пределами объекта:

var Class = function(p){
this.p = p;
}
Class.prototype.tell = function(word){
alert(this.p + ' ' + word + ' ' + this.constructor.p);
// alert(this.p + ' ' + word + ' ' + Class.p);
}
Class.p = 'futurico';

var o = new Class('karaboz');
o.tell('love'); // выводит 'karaboz loves futurico';

Замыкание (closure)

Закрытые и привилегированные методы возможны в JavaScript благодаря тому, что называется замыканием (closure). Замыкание — это функция, плюс все те лексические переменные из охватывающего контекста, которые она использует. Когда мы используем оператор function, мы всегда создаем не функцию, а именно замыкание. Замыкание 'помнит' значения всех переменых, которые существовали в контексте, создающем это замыкание, даже когда функция используется уже вне создавшего ее контекста.

var createFunc = function(param){
var closureParam = param;
// замыкание
var returnedFunc = function(){alert(closureParam);}
return returnedFunc;
}

var f = createFunc('karaboz');

Теперь, если мы посмотрим на переменную f, мы увидим, что это обычная функция, в теле которой заключен параметр closureParam, который неопределен нигде в окружающем f контектсе и по идее должен выдавать ошибку:

alert(f); // выведет: function(){alert(closureParam);}

Однако ошибки не будет, функция function(){alert(closureParam);} благодаря эффекту замыкания помнит closureParam из контекста, породившего ее:

f(); // выведет 'karaboz'

Если вспомнить описанный выше привилегированный метод .tellSecret, то теперь можно понять, как он работает. Метод помнит как закрытую функцию count(), так и закрытое свойство secret, объявленные в создающем .tellSecret контексте. При этом, когда внутри .tellSecret вызывается count(), эта последняя функция, в свою очередь, помнит использующуюся в ее теле переменую count.

Все публикации по теме ООП в JavaScript

Комментарии (7) на “ООП в Java Script (3): Свойства и методы класса”

  1. Zeroglif:

    > Свойства и методы класса (члены класса) могут быть открытыми (public), закрытыми (private), привилегированными (privileged) и статическими (static).
    Я бы всё-таки сделал небольшую, но важную ремарку про то, что всё сказанное не имеет прямого отношения к javascript 1.x, в нём не заложено, а может быть рассмотрено в качестве попытки калькировать/эмулировать некоторые идеи, заложенные в других языках, например, в класс-ориентированных. Нет классов, не модификаторов и т.д. и т.п.

    > переменные, переданные в качестве параметров в функцию-конструтор
    Формальные параметры.

    > Свойствa secret, count и метод counter создаются в объекте при его инициализации.
    К инициализируемому объекту эти свойства не имеют отношения, создаются не в нём, а в объекте активации функции-конструктора (Activation Object). Это для тех, кто будет читать буквально.

    > Замыкание (closer)
    Closure.

  2. Randoom:

    >Метод помнит как закрытую функцию count(), так и закрытое свойство secret, объявленные в создающем .tellSecret контексте. При этом, когда внутри .tellSecret вызывается count(), эта последняя функция, в свою очередь, помнит использующуюся в ее теле переменую count.

    f-ция = counter(), а не count()

  3. Михайлов Денис:

    За static - спасибо.

  4. karaboz:

    2 Zeroglif - спасибо за ценные уточнения
    2 Randoom - опечатку поправил (=

  5. Болт:

    Весьма интересно !

  6. feedbee:

    контектсе и по идее должен выдавать ошибку

  7. feedbee:

    Сорри, случайно запостилось. Сообщение выше — цитата из статьи. Там грамматическая ошибка в первом слове.

Оставить комментарий

Вам нужно войти, чтобы оставить комментарий.