Реальный пиарJavaScriptJquery → Некоторые концепции JavaScript, необходимые для эффективного применения jQuery

Некоторые концепции JavaScript, необходимые для эффективного применения jQuery

JavaScript

Эта статья написана «по мотивам» одной из глав книги «jQuery – подробное руководство по продвинутому JavaScript». Информация, содержащаяся в этой главе, показалась мне настолько полезной, что я не мог не поделиться ей. Здесь не освещаются все концепции языка – внимание уделено лишь тем, понимание которых поможет эффективнее овладеть библиотекой jQuery.

Итак, первое на чем мы остановим свое внимание – это определение и работа с функциями, с использованием подхода при котором они являются обычными объектами JavaScript. Но для того, чтобы к этому подойти, давайте сначала посмотрим, как создаются
Объекты в JavaScript1 var card = new Object();

Весьма просто, но совсем неинтересно, поскольку наш объект не содержит никакой информации. Давайте исправим это:1 var card = new Object();
2 card.firstname = 'Ivan';
3 card.lastname = 'Ivanov';
4 card.year = '1974';
5 card.employed = new Date(2004, 1, 12);

Это уже что-то полезное – создав новый экземпляр объекта, мы присвоили его переменной card и наполнили свойствами различных типов: строка, число, и дата.

Что же получается? Получается, что объект JavaScript – это набор свойств, каждое из которых состоит из имени и значения. При этом в качестве имени может выступать только строка, а вот значением (и это важный момент!!!) может быть и строка, и число, и массив, и конечно функция…

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

Давайте немного усложним наш код, который мы используем в качестве примера:1 var card = new Object();
2 card.firstname = 'Ivan';
3 card.lastname = 'Ivanov';
4 card.year = '1974';
5 card.employed = new Date(2004, 1, 12);
6 var phone = new Object();
7 phone.home = '(495)353-5353';
8 phone.mobile = '(903)261-1777';
9 card.phone = phone;

мы создали еще один объект, который содержит номера телефонов и сделали этот объект значением свойства нашего первого объекта.

А теперь попробуем записать все тоже самое в литеральной нотации, плавно двигаясь к тому синтаксису, который присутствует в jQuery-коде практически повсеместно.01 var card = {
02 firstname : 'Ivan',
03 lastname : 'Ivanov',
04 year : '1974',
05 employed : new Date(2004, 1, 12),
06 phone : {
07 home : '(495)353-5353',
08 mobile : '(903)261-1777'
09 }
10 };

Вот собственно такая форма записи и называется JSON – посмотрите, насколько проста и понятна структура:

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

Давайте теперь отметим для себя еще один очень важный момент, воспользовавшись следующим простым примером:1 var someVar = 'В лесу родилась елочка!';

Простейшая инструкция, в которой переменной присваивается экземпляр объекта String. Если мы попробуем выполнить:1 alert(someVar);

увидим то, что и ожидали – сенсационное сообщение о том, что в лесу родилась елочка. Как Вы думаете, что мы увидим после выполнения следующего кода?1 alert(window.someVar);

Можете попробовать, но сразу скажу, что в результате получится абсолютно тоже самое сообщение! Поскольку инструкции эквивалентны, то какой же вывод из этого можно сделать?

Правильно! Когда ключевое слово var используется за пределами какой-либо функции, на глобальном уровне, оно является всего лишь ссылкой на свойство объекта window.

Ну вот, с объектами мы более-менее разобрались. Но давайте кратко сформулируем то, о чем мы говорили. Итак:

- объект в JavaScript – это неупорядоченный набор свойств;
- свойство состоит из имени и значения;
- объекты можно объявлять с помощью литералов;
- глобальные переменные – есть свойства объекта window;
Функция как объект JavaScript

Вот теперь мы готовы к тому, чтобы вернуться к тому утверждению, что функции в JavaScript можно рассматривать как обычные объекты. Почему же в JavaScript функцию можно считать обычным объектом? Давайте возьмем для сравнения объекты других типов, например String или Number.

Если объекты String или Number определяются соответствующими конструкторами, то функции также определяются конструктором, в данном случае конструктором Function. Точно также, как и другие объекты функции могут:

- присваиваться переменным и свойствам объектов
- передаваться в виде параметров
- возвращаться как результат других функций
- создаваться с использованием литералов

Но есть на первый взгляд одно очень существенное отличие от тех же упомянутых объектов String или Number – у функции есть имя! Но это только на первый взгляд.

Посмотрим простенький пример:1 function hello() {
2 alert('Hello, world!');
3 }

такая запись очень часто используется для создания глобальных функций, но это совершенно не означает, что мы только что создали функцию с именем hello. Вспомните наши примеры с ключевым словом var. Тут практически тоже самое, только в примере с функцией ключевое слово function автоматически создает экземпляр объекта и присваивает его свойству объекта window. А имя этого свойства совпадает с именем нашей функции. Т.е. мы могли бы написать так:1 hello = function () {
2 alert('Hello, world!');
3 }

или даже так:1 window.hello = function () {
2 alert('Hello, world!');
3 }

Это есть синтаксис литерала функции – привыкайте, в jQuery-коде Вы будете использовать такую форму записи очень часто. Но самый главный вывод, который мы должны сделать – экземпляры Function являются значениями!!!, которые можно присвоить переменным, свойствам или параметрам, через которые на них можно ссылаться.
Функции обратного вызова

Следующий шаг – попробуем передавать функцию в качестве параметра и тут же разберем одно из самых распространенных понятий – функция обратного вызова. Смотрим код:1 function hello() {
2 alert('Hello, word!');
3 }
4 setTimeout(hello, 5000);

Объявляем функцию с именем hello и устанавливаем таймер на 5 секунд. Смотрите, передача функции в качестве параметра ничем не отличается от передачи любого другого значения – в первом параметре мы передали функцию, а во втором – число. Когда время таймера истечет, будет вызвана функция hello. Поскольку метод setTimeout() делает вызов функции в нашем собственном программном коде – эту функцию называют функцией обратного вызова.

Однако есть более изящный способ записи этого кода:1 setTimeout(function(){ alert('Hello, word!'); }, 5000);

если функцию не требуется вызывать где-то в другом месте страницы, нет никакой необходимости создавать свойство hello в объекте window. Такой подход будет очень часто встречаться в программном коде jQuery.
Реализация this в JavaScript

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

Давайте вернемся к примеру и немного дополним его:01 var card = {
02 firstname : 'Ivan',
03 lastname : 'Ivanov',
04 year : '1974',
05 employed : new Date(2004, 1, 12),
06 phone : {
07 home : '(495)353-5353',
08 mobile : '(903)261-1777'
09 },
10 showData : function() {
11 return this.lastname+'
12 '+this.firstname+'
13 '+this.phone.mobile;
14 }
15 };

К первоначальному коду мы добавили свойство с именем showData, которое ссылается на экземпляр Function. Если теперь вызвать функцию через свойство:1 alert(card.showData());

то в качестве контекста функции будет установлен экземпляр объекта на который указывает card. В результате мы увидим следующее:

Ivanov Ivan (903)261-1777

Ну это все вполне естественно, гораздо более интересен следующий пример. JavaScript позволяет четко установить, что будет использоваться в качестве контекста функции. Вызывая функцию с помощью методов call() или apply() экземпляра Function, мы можем передать в качестве контекста все, что угодно.01 var obj1 = { myProperty: 'object 1' };
02 var obj2 = { myProperty: 'object 2' };
03 var obj3 = { myProperty: 'object 3' };
04 window.myProperty = 'object window';
05
06 function showProperty() {
07 return this.myProperty;
08 }
09
10 obj1.identifyMe = showProperty;
11
12 alert(showProperty());
13 alert(obj1.identifyMe());
14 alert(showProperty.call(obj2));
15 alert(showProperty.apply(obj3));

Определили три простых объекта, у каждого из которых есть свойство myProperty. Добавили свойство myProperty в экземпляр объекта window. Определили глобальную функцию, которая возвращает значение свойства myProperty для любого объекта, используемого в качестве контекста этой функции. И еще присвоили эту же самую функцию свойству с именем identifyMe объекта obj1.

Дальше самое интересное – четыре раза мы вызываем один и тот же экземпляр функции другим способом и посмотрите, что получается:
- в первом случае вызываем функцию как глобальную и контекстом функции является экземпляр объекта window о чем свидетельствует текст в окне предупреждения – «object window«.
- во втором случае вызываем функцию как свойство объекта obj1 и контекстом функции становится этот объект. Текст в окне предупреждения – «object 1«.
- в третьем случае используем метод call() объекта Function и контекстом функции становится объект, переданный методу call() в качестве первого параметра. Текст в окне предупреждения – «object 2«.
- наконец в четвертом случае используем метод apply(), передавая ему в качестве первого аргумента obj3, и получаем текст в окне предупреждения – «object 3«.

Пример можно открыть в отдельном окне.

Вывод такой: функция fn действует как метод объекта ob, когда объект ob выступает в качестве контекста при вызове функции fn.
Что такое замыкание?

Замыкание (closure) – это экземпляр Function вместе с локальными переменными из его окружения, необходимыми для выполнения.

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

Лучше всего пояснить это на простом примере (здесь уже используем библиотеку jQuery):1 $(function(){
2 var local = 1;
3 window.setInterval(function(){
4 $('#result').append(new Date()+
5 ' значение local = '+local+' ');
6 local++;
7 }, 5000);
8 });

После загрузки DOM объявляем переменную local и присваиваем ей числовое значение 1. С помощью метода setInterval() взводим таймер, который будет срабатывать каждые 5 секунд. В качестве функции обратного вызова для таймера, определяем функцию, которая каждые пять секунд будет добавлять текущее время и значение переменной local. Кроме того, при каждом срабатывании таймера значение переменной local должно увеличиваться на единицу.

Пример можно открыть в отдельном окне.

Можно было подумать, что поскольку функция обратного вызова запустится только лишь спустя 5 секунд после готовности DOM, то во время выполнения функции переменная local окажется неопределенной, ведь код в котором определяется local выходит из области видимости, как только обработчик события готовности DOM заканчивает свою работу.

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

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

Посмотрите такой код:1 this.id = 'someID';
2 $('*').each(function(){
3 alert(this.id);
4 });

Мы могли бы ожидать, что в окне предупреждения для каждого элемента будет раз за разом отображаться значение someID, однако это совсем не так. Мы увидим окно предупреждений столько раз, сколько элементов будет отобрано в объект jQuery и каждый раз будет отображаться значение атрибута id следующего элемента (или пустое окно предупреждения, если такого атрибута нет). Это происходит потому, что у каждого вызова функции собственный контекст, и в данном случае контекстом является элемент из объекта jQuery.

Давайте немного исправим пример:1 this.id = 'someID';
2 var someVar = this;
3 $('*').each(function(){
4 alert(someVar.id);
5 });

Переменная someVar становится частью замыкания и будет доступна внутри функции обратного вызова. Такой код будет раз за разом выдавать в окне предупреждения одно и тоже значение – someID.

Ну, вот вроде бы и все. Осталось сказать, что если твердо усвоить все эти понятия, то создавать эффектные и эффективные сценарии на JavaScript с использованием jQuery будет гораздо проще…


Источник: http://www.linkexchanger.su

Рекомендуем



Как использовать виджет Accordion в качестве меню? А сегодняшняя статья написана благодаря довольно многочисленным вопросам и моему обещанию рассказать, как, используя accordion, сделать на его основе меню для сайта


Официальные плагины jQuery: Templates plugin Следует отметить, что команда Microsoft использовала свои немалые наработки в этих направлениях, как и команда проекта jQuery, и при хорошо сложившемся взаимодействии получились, на мой взгляд, отличные инструменты для разработчиков


Изготовление меню Характер работ: Разработка дизайна для специальных предложений от Шеф-повара