Объекты

Как оказалось, большинство всего с чем мы работаем в 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 подробно рассматривает такие темы как прототипы объектов, конструкторы и удаление свойств объектов.

Автор: Ребекка Мёрфи
Последнее изменение: 27.02.2024