Как оказалось, большинство всего с чем мы работаем в JavaScript является объектом — на самом деле, есть только пять типов значений, не являющихся объектами:
- строки (текст);
- логические (true/false);
- числа;
- undefined;
- null.
Эти значения называются примитивами, но даже некоторые из них можно рассматривать как если бы они были объектами — подробнее об этом узнаете через минуту. Но что такое объект? Давайте посмотрим на примере простого объекта:
var person = {
firstName : 'Баз',
lastName : 'Сендер'
};
Созданный нами объект содержит два свойства: firstName и lastName. Мы создали его с помощью «синтаксиса литеральных объектов» — то есть, установив набор пар ключ-значение в {}. Обратите внимание, что для каждой пары поставлено двоеточие между ключом и значением и запятая между каждой парой. Отметим также, что после последней пары ключ-значение нет запятой — если вы случайно поставите запятую после последней пары, то получите ошибки в старых браузерах.
Доступ к свойствам
Мы храним наш объект в переменной с именем person, которая позволяет легко получить доступ к свойствам объекта, используя нотацию с точкой или с квадратными скобками.
var person = {
firstName : 'Баз',
lastName : 'Сендер'
};
console.log( 'Имя: ' + person.firstName ); // нотация с точкой
console.log( 'Фамилия: ' + person[ 'lastName' ] ); // нотация с квадратными скобками
Заметьте, что в нотации со скобками мы использовали строку в кавычках для имени свойства; в нотации с точкой мы просто использовали имя свойства без кавычек. Нотация со скобками является полезным подходом, если, скажем, позже вы сохраняете имя свойства в переменной:
var person = {
firstName : 'Баз',
lastName : 'Сендер'
};
var prop = 'lastName';
console.log( 'Фамилия: ' + person[ prop ] );
После создания объекта мы можем изменить его свойства.
var person = {
firstName : 'Баз',
lastName : 'Сендер'
};
person.firstName = 'Бен';
person.lastName = 'Альман';
console.log( 'Имя: ' + person.firstName );
console.log( 'Фамилия: ' + person.lastName );
Данный аспект JavaScript является одновременно и благословением и проклятием. Это означает, что объекты невероятно гибкие, но также означает, что не существует «конфиденциальности». Любой код может легко переписать значение свойства любого объекта, к которому он имеет доступ. Это ещё одна причина, почему важно хранить переменные за пределами глобальной области видимости — разве это нормально, когда другой код их меняет.
Методы объекта
Методы объекта — это просто свойства, значения которых являются функциями. Давайте добавим метод .greet() к нашему объекту person:
var person = {
firstName : 'Баз',
lastName : 'Сендер',
greet : function(name) {
console.log( 'Привет, ' + name );
}
};
person.greet( person.firstName );
Метод .greet() в данном примере получил в качестве аргумента строку name. Когда мы вызываем метод, то просто отправляем ему значение свойства firstName объекта person. Если бы мы хотели супер-гибкий метод .greet(), который может приветствовать любого, это то что нам нужно. Но, вероятно, больше смысла в том, что метод .greet() будет приветствовать конкретное лицо.
Понимание this
Внутри метода, а в действительности внутри любой функции, есть доступное нам специальное ключевое слово this. Оно относится к объекту, который является контекстом в котором функция была вызвана.
Когда мы вызываем person.greet(), контекстом объекта служит сам person. Это значит, что мы можем использовать this и получить доступ к свойству объекта person непосредственно из метода .greet().
Понимание this может невероятно запутать новых разработчиков JavaScript и вас должно утешить что jQuery в основном делает так, что вам пока и не нужно понимать. Однако, обсуждение объектов и методов не является полным, если вообще не упомянуть о this, хотя бы немного. Короче говоря, если этот раздел вас смущает, то смело пропускайте его и возвращайтесь к нему когда будете готовы.
Давайте посмотрим, как мы могли бы использовать this в нашем методе.
var person = {
firstName : 'Баз',
lastName : 'Сендер',
greet : function() {
console.log( 'Привет, ' + this.firstName );
}
};
person.greet();
Не так уж и запутанно, верно? Путаница возникает, потому что смысл this может поменяться — как упоминалось ранее, это зависит от контекста, в котором функция была вызвана! Рассмотрим следующий код:
Внимание! Некорректный код
var person = {
firstName : 'Баз',
lastName : 'Сендер',
greet : function() {
console.log( 'Привет, ' + this.firstName );
}
};
var sayIt = person.greet; // сохраняем метод в переменной
sayIt(); // выводит: 'Привет, undefined' — ой-ой
Когда мы сохраняем метод .greet() в переменной sayIt, а затем вызываем sayIt(), контекст объекта меняется на глобальный объект window, а не объект person. Поскольку у объекта window нет свойства firstName, мы получаем undefined при попытке получить к нему доступ.
Что делать разработчику? Во-первых, следует знать, что сохранение методов объекта в переменных может иметь непредсказуемые последствия для this. Во-вторых, помните что вы можете зафиксировать значение this на желаемое с помощью методов .call() или .apply() для самой функции.
var person = {
firstName : 'Баз',
lastName : 'Сендер',
greet : function() {
console.log( 'Привет, ' + this.firstName );
}
};
var sayIt = person.greet;
sayIt.call( person );
Оба метода очень похожи. Метод .apply() также позволяет передавать аргументы в функцию, к которой мы обращаемся. Представьте, что в наш метод .greet() передаются некоторые аргументы; мы могли бы передать их с помощью .call(), вот так:
var person = {
firstName : 'Баз',
lastName : 'Сендер',
greet : function(greeting, punctuation) {
console.log( greeting + ', ' + this.firstName + punctuation );
}
};
var sayIt = person.greet;
sayIt.call( person, 'Привет', '!!!' );
Мы могли бы сделать то же самое через .apply(), но тогда придётся передавать аргументы в виде единого массива, вместо отдельных аргументов:
var person = {
firstName : 'Баз',
lastName : 'Сендер',
greet : function(greeting, punctuation) {
console.log( greeting + ', ' + this.firstName + punctuation );
}
};
var sayIt = person.greet;
sayIt.apply( person, [ 'Привет', '!!!' ] );
Подробнее об этих методах рассказывается в документации на MDN о .call() и apply().
Объекты в jQuery
Мы лишь поверхностно освоили объекты, но теперь зная основы вы научитесь как работать с объектами jQuery. В базовом jQuery вы будете широко использовать объекты, чтобы задать параметры конфигурации. Например, вы можете указать объект и тем самым одновременно изменить несколько свойств CSS для элемента:
$('#main').css({
color: 'red',
border: '1px solid blue'
});
Что касается this, jQuery, как правило, управляет его значением. В случае обработчиков событий, this будет ссылаться на элемент, к которому привязан обработчик; в случае перебора элементов в выборке, this будет ссылаться на текущий элемент. Вам не стоит сильно беспокоиться о понимании this во время начального обучения — это просто хорошая штука и помните о ней, пока ваше обучение продолжается.
Дальнейшее чтение
Руководство по JavaScript на MDN подробно рассматривает такие темы как прототипы объектов, конструкторы и удаление свойств объектов.