Метод – это функция JavaScript, вызываемая через объект. Вспомните, что функции – это значения и что в имени, с которым определена функция, нет ничего особенного – функция может быть присвоена любой переменной или даже любому свойству объекта. Если у нас есть функция f и объект o, мы можем определить метод с именем m, написав следующее:
o.m = f;
Определив метод m() объекта o, мы сможем вызывать его так:
o.m();
А вот как можно вызвать m(), если он требует двух аргументов:
o.m(x, x+2);
Методы имеют одну очень важную особенность: объект, через который вызывается метод, становится значением ключевого слова this в теле этого метода. Например, когда мы вызываем o.m(), тело метода ссылается на объект o с помощью ключевого слова this.
Прежде чем обсуждать ключевое слово this, выясним, зачем вообще нужны методы. Любая функция, используемая в качестве метода, обязательно получает дополнительный аргумент – объект, через который она вызвана.
Обычно метод выполняет некоторую операцию над объектом, поэтому синтаксис вызова метода – очень изящный способ выразить тот факт, что функция работает с объектом. Сравните следующие две строки кода:
rect.setSize(width, height);
setRectSize(rect, width, height);
Эти две строки могут выполнять абсолютно одну и ту же операцию с объектом rect, но синтаксис вызова метода в первой строке более четко показывает, что направлена операция именно на объект rect, или на ее цель. (Еслисинтаксис первой строки не кажется вам более естественным, то вы, видимо, новичок в объектно-ориентированном программировании. Когда вы приобретете некоторый опыт, оно вам понравится !)
Хотя и полезно рассматривать функции и методы по-разному, между ними не так много отличий, как может показаться на первый взгляд. Вспомните, что функции – это значения, хранящиеся в переменных, а переменные – это свойства глобального объекта. Следовательно, вызывая функцию, вы фактически вызываете метод глобального объекта. Внутри такой функции ключевое слово this ссылается на глобальный объект. Реальное отличие состоит в цели и назначении: методы пишутся для выполнения каких-либо операций с объектом this, а функции обычно работают изолированно и не используют объект this.
Типичное применение методов более ясно иллюстрируется в примере 8.2, в котором мы возвращаемся к объектам Rectangle и показываем, как определить и вызвать метод, работающий с объектами Rectangle.
Пример 8.2. Определение и вызов метода
// Эта функция использует ключевое слово this, поэтому нет смысла
// вызывать ее саму по себе, она должна быть сделана методом какого-
// либо объекта, в котором определены свойства «width» и «height».
function compute_area()
{
return this.width * this.height;
}
// Создаем новый объект Rectangle с помощью конструктора, определенного ниже
var page = new Rectangle(8.5, 11);
// Определяем метод путем присваивания функции свойству объекта.
page.area = compute_area;
// Вызываем новый метод:
var a = page.area(); // a = 8.5*11 = 93.5
Один недостаток в примере 8.2 очевиден: перед тем как вы сможете вызвать метод area() объекта rect, необходимо присвоить этот метод свойству объекта. Несмотря на то что мы можем вызвать метод area() для конкретного объекта с именем page, мы не можем вызвать его для других объектов Rectangle, не присвоив им заранее этот метод. Это вам быстро надоест. Пример 8.3 определяет некоторые другие методы и показывает, как с помощью функции-конструктора они могут быть автоматически присвоены всем объектам Rectangle.
Пример 8.3. Определение методов в конструкторе
// Сначала определим некоторые функции, которые будут использоваться как методы
function Rectangle_area() { return this.width * this.height; }
function Rectangle_perimeter() { return 2*this.width + 2*this.height; }
function Rectangle_set_size(w,h) { this.width = w; this.height = h; }function Rectangle_enlarge() { this.width *= 2; this.height *= 2; }
function Rectangle_shrink() { this.width /= 2; this.height /= 2; }
// Затем определим метод-конструктор для наших объектов Rectangle
// Конструктор инициализирует свойства, а также присваивает методы.
function Rectangle(w, h)
{
// Инициализация свойств объекта.
this.width = w;
this.height = h;
// Определение методов объекта.
this.area = Rectangle_area;
this.perimeter = Rectangle_perimeter;
this.set_size = Rectangle_set_size;
this.enlarge = Rectangle_enlarge;
this.shrink = Rectangle_shrink;
}
// Теперь мы можем вызывать методы сразу после создания объекта Rectangle.
var r = new Rectangle(2,2);
var a = r.area();
r.enlarge();
var p = r.perimeter();
Прием, показанный в примере 8.3, также имеет недостаток. В этом примере конструктор Rectangle() устанавливает семь свойств для каждого инициализируемого им объекта Rectangle, даже несмотря на то, что пять из этих свойств имеют постоянные значения, одинаковые для всех прямоугольников. Каждое из свойств занимает место в памяти; добавив методы к нашему классу Rectangle, мы более чем втрое увеличили требования к памяти, занимаемой каждым объектом Rectangle. К счастью, в JavaScript есть возможность обойти это препятствие: объекту позволено наследовать свойства от объекта-прототипа.