ООП в Java Script (2): Классы

Итак, класс — это шаблон, описывающий свойства и методы, которыми будет обладать любой объект, созданный на основе этого класса. Чтобы создать свой собственный класс в JavaScript, мы должны написать функцию-конструктор:

// Функция-конструктор - это обычная функция
var Class = function(p){
alert('My name is constructor');
this.p = p;
}

А чтобы создать объект этого нового класса, мы должны вызвать его как обычную функцию, используя при этом ключевое слово new. При этом ключевое слово this внутри функции-конструтора теперь будет указывать на вновь созданный объект:

var o = new Class('karaboz');
alert(o); // выводит [Object object]
alert(o.p); // выводит 'karaboz' - теперь это свойство объекта o

Если попытыться переменной o просто присвоить вызов функции Class() - без ключевого слова new, то никакого объекта создано не будет:

var o = Class('karaboz'); // эквивалентно вызову window.Class()
alert(o); // выводит undefined, а именно то, что вернула функция Class()
alert(window.p); // выводит 'karaboz' - теперь это свойство глобального объекта window

При создании функции, JavaScript автоматически создает для нее пустое свойство .prototype. Любые свойства и методы, записанные в .prototype функции-конструтора станут доступными как свойства и методы объектов, созданных на основе этой функции. Это является основой для описания шаблона (класса), по которому и будут создаваться объеты.

Class.prototype.method = function(){
alert('my name is .method');
}

Теперь мы можем вызывать этот метод, как метод самого объекта:

o.method(); // работает!

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

Так, при создании объекта, в нем уже существует свойство .constructor, которое указывает на функцию-конструктор, создавшую этот объект:

alert(o.constructor == Class); // выводит true 

Заметим, что мы не определяли такого свойства в самом объекте. Интерпретатор, не найдя свойство .constructor в объекте, берет его из .prototype функции-конструктора, создавшей объект. Проверим:

alert(Class.prototype.constructor == Class); // выводит true

Следует обратить внимание, что .prototype существует только для функции-конструктора, но не для самого объекта, созданного на его основе:

alert(o.prototype); // выводит undefined
alert(o.constructor.prototype); // выводит [Object object]

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

var s = 'karaboz';

s.constructor.prototype.tell = function(){
alert(this);
}

s.tell(); // теперь это не выдает ошибку, а выводит 'karaboz'

Задать новое свойство или метод для встроенных типов объектов можно и напрямую — через встроенную функцию-конструтор этих объектов:

String.prototype.tell = function(){
alert(this);
}

Кстати, мы в очередой еще подтвердили утверждение о том, что все в JavaScript есть объект (=

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

Комментарии (11) на “ООП в Java Script (2): Классы”

  1. Zeroglif:

    > При создании функции, JavaScript автоматически создает для нее пустое свойство .prototype
    Вряд ли можно назвать это свойство "пустым", его значением является ссылка на объект, который в свою очередь тоже не "пуст".

    > При вызове свойства объекта, оно ищется сначала в самом объекте, и если его там не оказывается, то интепретатор смотрит в .prototype функции-конструктора, создавшей объект.
    К моменту обращения к свойству объекта, функция-конструктор может уже не существовать, а свойство prototype может содержать совершенно другое значение (не прототип объекта), поэтому интерпретатор к свойству prototype конструктора вообще не обращается, поиск осуществляется по другой неявной цепочке. Это важно. В следующих статьях вы ещё пару раз ошибочно пишите про "поиск в свойстве (объекте) .prototype функции-конструктора", плодить на тот же счёт комментарии не буду, ограничусь этим.

    > мы в очередой еще подтвердили утверждение о том, что всё в JavaScript есть объект
    Рррр… Не подтвердили. Не всё. ;-)

  2. Михайлов Денис:
    var s = 'karaboz';
    s.constructor.prototype.tell = function()
    {
    	alert(this);
    }
    s.tell();
    

    "Добавлять" таким способом методы для созданных объектов не просто плохо, а очень очень очень плохо. За такое надо отрубать руки. У неопытного программиста может создастся иллюзия что этот метод добавился только для его объекта "s", а это не так. Но это пол беды. Если каждый "воодушевленный" этим способом начнет добавлять (переопределять) свои прекрасные методы, то все участники процесса кодирования будут сильно удивлены новыми недокументированными возможностями привычных для них объектов.

    Если и требуется расширить функционал объекта String, нужно это делать централизовано и одни раз используя исключительно String.prototype….

  3. karaboz:

    Михайлов Денис, абсолютно с вами согласен по поводу отрубания рук (= Я же только хотел "прочувствовать" природу и возможности JS, не более того (=

  4. Алекс:

    Поменял бы я на вашем месте ключевое слово Class, можно принять его за ключевое..

  5. Алекс:

    В смысле просто бы поменял, ведь во многих языках программирования это ключевое слово, поэтому легко и просто могут принять и за ключевое в JS…

  6. karaboz:

    Алекс, вы правы, было бы прозрачней и надёжней дать другое имя для функции-конструктора.

  7. Petrusha:

    Следует обратить внимание, что .prototype существует только для функции-конструктора, но не для самого объекта

  8. Alexey R.:

    А можно ли создать .prototype для метода внутри .prototype?

  9. Alexey R.:

    Я имел ввиду, создается ли прототайп для каждой функции в прототайп?

  10. Максим:

    Не очень красивые примеры, я раньше тоже так кодировал. Сейчас в сети наиболее распространена техника с использованием базового класса Дина Эдвардса - этот класс дает полную иллюзию что программируешь на С++ или Java, Что-то подобное используется в библиотеке Prototype. Я тут на досуге решил с Дином поконкурировать и создал свою версию базового класса для ОО - http://ru.ztools.org/doc/oo/. Данное решение имеет полноценное наследование, доступ к функциям предка - а главное нет никаких prototype при объявлении классов, а главное оно в разы компактнее чем у Дина. Буду рад если найдете недостатки у данного способа. Конструктивная критика приветствуется.

  11. Артем Шматок:

    Полезная статья. особенно для таких новичков как я) Воспльзуюсь советами.

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

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