Чтение онлайн

ЖАНРЫ

Основы программирования на JavaScript

Кан Марк

Шрифт:

JavaScript слегка отличается от стандартной объектно-ориентированной структуры Class. Вместо использования классов для создания объектов, каждая функция в JavaScript может эффективно действовать как класс. Мы используем концепцию вложенных функций, называемую прототипированием (Prototyping), для выполнения таких же вещей, как и языки со структурами Class. Если вы знакомы с ОО-языком на основе классов, то прототипирование может показаться сначала непривычной концепцией, но она предлагает большие возможности и часто является значительно более гибкой с точки зрения программирования, чем другие методы.

Для начала необходимо объяснить, как

объекты действуют в JavaScript. Объекты позволяют определить переменную и задать затем для этой переменной любое число свойств. Чтобы понять это, давайте посмотрим на простой пример:

var myObj = new Object;

myObj.a = 5;

myObj['b'] = 10;

myObj.c = 20;

myObj.getTotal = function{

alert(this.a+this.b+this.c);

};

// или

var myObj = {a:5, b:10, c:20,

getTotal:function { alert(this.a+this.b+this.c); }};

Оба эти фрагмента кода создают одну и ту же переменную myObj. Первый пример использует синтаксис new Object, а затем определяет все свойства одно за другим. Второй фрагмент кода является сокращенной нотацией, которая делает в точности то же самое. Мы имеем теперь переменную myObj. myObj содержит три переменные для целых чисел: a, b и c. Для доступа к любой из них мы просто используем myObj.a или myObj['a']. Можно видеть, что myObj имеет также в качестве свойства функцию getTotal. Мы обращаемся к getTotal таким же образом, как и к свойствам a, b и c: myObj.getTotal. Функция getTotal обращается к переменным в переменной myObj с помощью this. При выполнении кода внутри функции в объекте this ссылается на объект. В данном случае this ссылается на сам объект myObj.

Как можно видеть, объекты в JavaScript являются чрезвычайно полезными. К сожалению, часто приходится объявлять слишком много информации каждый раз, когда мы хотим создать объект. Например, давайте создадим объект Animal:

var myAnimal = {

name: 'felix',

species: 'cat',

talk: function{ alert('Meow!'); },

callOver: function{ alert(this.name+' ignores you'); },

pet: function{ alert('Purr!'); }

}

Мы имеем переменную myAnimal, которая представляет кота (cat) с именем Феликс (felix). Однако, если потребуется создать другого кота, нам понадобиться ввести все это снова. Здесь на помощь приходит объектно-ориентированный подход. Вместо перепечатки всякий раз всего объекта можно определить функцию, которая создает для нас аналогичный объект:

function Cat(name){

this.name = name;

this.species = 'Cat';

this.talk = function{ alert('Meow!'); }

this.callOver = function{ alert(this.name+' ignores you'); },

this.pet = function{ alert('Purr!'); }

}

var felix = new Cat('Felix');

var sam = new Cat('Sam');

var patty = new Cat('Patty');

felix.pet; // выводит 'Purr!'

sam.callOver; // выводит 'Sam ignores you'. Просто, как кот!

alert(patty.species); // выводит 'Cat'

В этом примере создана одна функция Cat,

а затем создаются три новых кота с помощью этой функции: Felix, Sam и Patty. Каждый из этих котов имеет одинаковые функции: talk, callOver и pet, и каждая из них имеет свойство species, заданное как 'cat'. И подобно всем котам, они в равной степени своенравны.

Обычно говорят, что felix, sam и patty являются экземплярами одного объекта: Cat. Код самой функции Cat называется конструктором. Мы передаем ей переменную name и используем ее для задания this.name. К сожалению, при объявлении каждой функции Cat в конструкторе в действительности создается новая копия каждой функции всякий раз при создании нового Cat. Так как функции talk, callOver и pet являются идентичными, то нам в действительности требуется только одна копия каждой функции. Здесь на помощь приходит прототипирование.

Можно переписать функцию Cat таким образом, чтобы каждая функция объявлялась только один раз:

function Cat(name){

this.name = name;

}

Cat.prototype.species = 'Cat';

Cat.prototype.talk = function{ alert('Meow!'); };

Cat.prototype.callOver = function{ alert(this.name+' ignores you'); };

Cat.prototype.pet = function{ alert('Purr!'); };

Синтаксис этого метода немного отличается от предыдущего. Вместо объявления всех свойств и методов внутри функции Cat, они теперь объявляются с помощью Cat.prototype. Это может показаться более сложным, но предлагает много преимуществ. Предположим, например, что надо добавить новую функцию sleep для каждого имеющегося cat. Это можно сделать двумя способами. Первый: можно добавить функцию sleep в felix, sam и patty. Это, однако, не только трудоемко, но также и неэффективно. Если бы имелось 500 cat, то потребовалось бы сначала отследить всех этих 500 котов, а затем добавить функцию каждому cat.

Однако с помощью прототипов можно добавить функцию sleep всем cat одновременно:

Cat.prototype.sleep = function{ alert(this.name+' falls asleep'); };

Этот способ не только быстрее, но к тому же нам больше не требуется отслеживать каждого cat, чтобы добавить функцию sleep.

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

function Cat(name){

this.name = name;

}

Cat.prototype = {

species: 'Cat',

talk: function{ alert('Meow!'); },

callOver: function{ alert(this.name+' ignores you'); },

pet: function{ alert('Pet!'); }

}

Важно отметить, что с помощью этого метода можно задать свойства функции только один раз. После этого необходимо использовать предыдущий метод.

Object.prototype.method = function{ ... }.

Поделиться с друзьями: