09. Функции. Часть 3. Конструкторы

Классы и объекты

В объектно-ориентированных языках программирования объекты рассматриваются как экземпляры класса.

Классы в JavaScript можно описывать при помощи функции-конструктора, а объекты — экземпляры класса — строить с помощью оператора new и вызова конструктора:

var объект = new Конструктор();

Что такое объект

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


var ob = {x:1,y:2}; 

Что такое класс

В объектно-ориентированных языках программирования объекты рассматриваются как экземпляры класса. Класс — это «документация» на однотипные объекты, своего рода шаблон, — в нём описываются свойства и методы, которые должны принадлежать каждому экземпляру класса.

Таким образом, класс позволяет создавать не один уникальный объект (подобный объекту ob, приведённому выше), а целое множество однотипных объектов.

Во многих объектно-ориентированных языках программирования для описания класса имеется специальная синтаксическая конструкция, например, в Си++ — это конструкция class.

Вот как в Си++ можно определить класс для работы с прямоугольниками:


// Описание класса Rectangle (прямоугольник)
// Инициализирует в экземпляре класса переменные width и height
// Создаёт функцию square() -- вычисление площади 
class Rectangle
{
  public:
  int width;  // Это переменная-член класса 
  int height; // Это переменная-член класса
  int square() {return width*height}; // Это функция-член класса
}

Описание класса не представляет собой какой-либо конкретный объект, а является шаблоном для создания объектов данного типа.

Слово Rectangle становится обозначением нового типа данных (наряду с int, char и другими встроенными типами).

Можно написать:


int z;           // Описана переменная z целочисленного типа 
Rectangle rect;  // Создан объект rect 
rect.width =  2; // Инициализирована переменная width в объекте rect
rect.height = 3; // Инициализирована переменная height в объекте rect
z = rect.square(); // Равно 6 -- результат работы метода square

В C++ можно описать функцию-конструктор. Делается это так:


// Описание класса Rectangle (прямоугольник)
// Инициализирует в экземпляре класса переменные width и height
// Создаёт функцию square() -- вычисление площади 
// Описывает функцию-конструктор
class Rectangle
{
  public:
  int width;  // Это переменная-член класса 
  int height; // Это переменная-член класса
  Rectangle(int x, int y) // Функция-конструктор класса. 
  {                       // Ее имя совпадает с именем класса
    width  = x;
    height = y;
  }
  int square() {return width*height}; // Это функция-член класса
}

Теперь можно написать:


int z;               // Описана переменная z целочисленного типа 
Rectangle rect(2,3); // Создан объект rect. Переменные объекта 
                     // инициализированы при помощи функции-конструктора
z = rect.square();   // Равно 6 -- результат работы метода square

В JavaScript нет специальной синтаксической конструкции для создания класса (хотя такая конструкция планируется в версии 2.0).

Но классы (как мы уже видели) в JavaScript можно задавать описанием функции-конструктора, а объекты — экземпляры класса — строить с помощью оператора new и вызова конструктора.

Замечание 1. Классы JavaScript имеют особенности, поэтому их часто называют не классами, а псевдоклассами (по отношению к классам таких языков программирования, как Си++, Java или C#). Мы всё же будем использовать термин «класс», ибо он короче, и правильно отражает суть: создание однотипных объектов на базе построенной «документации».

Замечание 2. Заметим, что описание любой функции — это «документация» на создание объекта вызова, внутри которого будет работать описанный код. В частности, формальные аргументы в объекте вызова превращаются в одноименные свойства, и в них заносятся значение фактических аргументов.

Посмотрим, как в JavaScript можно описать класс Rectangle, а затем создавать объекты, экземпляры этого класса.

Сначала опишем соответствующую функцию конструктор:


// Конструктор класса Rectangle
function Rectangle(width, height)
{
  // Свойства класса
  this.width  = width;
  this.height = height;

  // Методы класса
  this.square = function () { return this.width * this.height;};
}

А теперь будем создавать объекты — экземпляры этого класса, и работать с ними.


var rect1 = new Rectangle(1,2);   // Создали первый экземпляр
var rect2 = new Rectangle(10,20); // Создали второй экземпляр
alert(rect1.square()); // 2   -- нашли площадь первого прямоугольника
alert(rect2.square()); // 200 -- нашли площадь второго прямоугольника

Запуск примера: praxis/09/examples/01/test.htm

Замечание. Вспомним, как работает пара «new конструктор». Оператор new создает пустой объект и передает его в качестве неявного аргумента this конструктору. Конструктор создает в объекте свойства (и методы, которые ведь тоже есть свойства). В частности, инструкция


var rect1 = new Rectangle(1,2);

делает следующее.

  1. Создаётся (где-то в памяти) пустой объект (экземпляр класса Object).
  2. Конструктор Rectangle запускается в контексте созданного (пустого объекта). При этом:
    • 2.1. В объекте создается свойство width и ему присваивается значение 1 (результат выполнения инструкции this.width = width;)
    • 2.2. В объекте создается свойство height и ему присваивается значение 2 (результат выполнения инструкции this.height = height;)
    • 2.3. В объекте создается свойство square и ему присваивается значение функционального литерала function(){return this.width*this.height;}. (Нудно отметим, что экземпляр литерала создается где-то в памяти, а в свойство square записывается ссылка на него.)
  3. Переменная rect1 присваивается ссылка на созданный объект.