Javascript Object: создание объектов и работа. Работа с объектами в javascript - Используем функции - Теория и практика

Объекты

Объект является фундаментальным типом данных в языке JavaScript. Объект - это составное значение: он объединяет в себе набор значений (простых значений или других объектов) и позволяет сохранять и извлекать эти значения по именам.

Объект является неупорядоченной коллекцией свойств, каждое из которых имеет имя и значение. Имена свойств являются строками, поэтому можно сказать, что объекты отображают строки в значения. Такое отображение строк в значения может называться по-разному: возможно, вы уже знакомы с такой фундаментальной структурой данных, как «хеш», «словарь» или «ассоциативный массив». Однако объект представляет собой нечто большее, чем простое отображение строк в значения.

Помимо собственных свойств объекты в языке JavaScript могут также наследовать свойства от других объектов, известных под названием «прототипы». Методы объекта - это типичные представители унаследованных свойств, а «наследование через прототипы » является ключевой особенностью языка JavaScript.

Объекты в языке JavaScript являются динамическими - обычно они позволяют добавлять и удалять свойства - но они могут использоваться также для имитации статических объектов и «структур», которые имеются в языках программирования со статической системой типов. Кроме того, они могут использоваться (если не учитывать, что объекты отображают строки в значения) для представления множеств строк.

Любое значение в языке JavaScript, не являющееся строкой, числом, true, false, null или undefined, является объектом. И даже строки, числа и логические значения, не являющиеся объектами, могут вести себя как неизменяемые объекты (имеют объекты-обертки String, Number и т.п.).

Объекты являются изменяемыми значениями и операции с ними выполняются по ссылке, а не по значению. Если переменная x ссылается на объект, и выполняется инструкция var y = x; , в переменную y будет записана ссылка на тот же самый объект, а не его копия. Любые изменения, выполняемые в объекте с помощью переменной y , будут также отражаться на переменной x .

Свойство имеет имя и значение. Именем свойства может быть любая строка, включая и пустую строку, но объект не может иметь два свойства с одинаковыми именами. Значением свойства может быть любое значение, допустимое в языке JavaScript, или (в ECMAScript 5) функция чтения или записи (или обе).

В дополнение к именам и значениям каждое свойство имеет ряд ассоциированных с ним значений, которые называют атрибутами свойства :

    Атрибут writable определяет доступность значения свойства для записи.

    Атрибут enumerable определяет доступность имени свойства для перечисления в цикле for/in.

    Атрибут configurable определяет возможность настройки, т.е. удаления свойства и изменения его атрибутов.

До появления стандарта ECMAScript 5 все свойства в объектах, создаваемые программой, доступны для записи, перечисления и настройки. В ECMAScript 5 предусматривается возможность настройки атрибутов ваших свойств.

В дополнение к свойствам каждый объект имеет три атрибута объекта :

    Атрибут class содержит строку с именем класса объекта и определяет тип объекта.

    Флаг extensible (в ECMAScript 5) указывает на возможность добавления новых свойств в объект.

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

Объект базового языка

Это объект или класс объектов, определяемый спецификацией ECMAScript. Массивы, функции, даты и регулярные выражения (например) являются объектами базового языка.

Объект среды выполнения

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

Пользовательский объект

Любой объект, созданный в результате выполнения программного кода JavaScript.

Собственное свойство

Это свойство, определяемое непосредственно в данном объекте.

Унаследованное свойство

Это свойство, определяемое прототипом объекта.

Создание объектов

Объекты можно создавать с помощью литералов объектов, ключевого слова new и (в ECMAScript 5) функции Object.create() .

Литералы объектов

Самый простой способ создать объект заключается во включении в программу литерала объекта. Литерал объекта - это заключенный в фигурные скобки список свойств (пар имя/значение), разделенных запятыми. Именем свойства может быть идентификатор или строковый литерал (допускается использовать пустую строку). Значением свойства может быть любое выражение, допустимое в JavaScript - значение выражения (это может быть простое значение или объект) станет значением свойства.

Ниже приводится несколько примеров создания объектов:

Var empty = {}; // Объект без свойств var point = { x:0, y:0 }; // Два свойства var point2 = { x:point.x, y:point.y+1 }; // Более сложные значения var site = { "url site": "www..NET Framework", // и дефисами, поэтому исп. кавычки author: { // Значением этого свойства является firstname: "Alexandr", // объект. Обратите внимание, что surname: "Frolov" // имена этих свойств без кавычек. } };

В ECMAScript 5 (и в некоторых реализациях ECMAScript 3) допускается использовать зарезервированные слова в качестве имен свойств без кавычек. Однако в целом имена свойств, совпадающие с зарезервированными словами, в ECMA-Script 3 должны заключаться в кавычки. В ECMAScript 5 последняя запятая, следующая за последним свойством в литерале объекта, игнорируется. В большинстве реализаций ECMAScript 3 завершающие запятые также игнорируются, но IE интерпретирует их наличие как ошибку.

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

Создание объектов с помощью оператора new

Оператор new создает и инициализирует новый объект. За этим оператором должно следовать имя функции. Функция, используемая таким способом, называется конструктором и служит для инициализации вновь созданного объекта. Базовый JavaScript включает множество встроенных конструкторов для создания объектов базового языка. Например:

Var o = new Object(); // Создать новый пустой объект: то же, что и {} var a = new Array(); // Создать пустой массив: то же, что и var d = new Date(); // Создать объект Date, представляющий текущее время var r = new RegExp("js"); // Создать объект RegExp для операций сопоставления с шаблоном

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

Object.create()

Стандарт ECMAScript 5 определяет метод Object.create(), который создает новый объект и использует свой первый аргумент в качестве прототипа этого объекта. Дополнительно Object.create() может принимать второй необязательный аргумент, описывающий свойства нового объекта.

Object.create() является статической функцией, а не методом, вызываемым относительно некоторого конкретного объекта. Чтобы вызвать эту функцию, достаточно передать ей желаемый объект-прототип:

// obj наследует свойства x и y var obj = Object.create({x:1, y:2});

Чтобы создать объект, не имеющий прототипа, можно передать значение null, но в этом случае вновь созданный объект не унаследует ни каких-либо свойств, ни базовых методов, таких как toString() (а это означает, что этот объект нельзя будет использовать в выражениях с оператором +):

// obj2 не наследует ни свойств, ни методов var obj2 = Object.create(null);

Если в программе потребуется создать обычный пустой объект (который, например, возвращается литералом {} или выражением new Object()), передайте в первом аргументе Object.prototype:

// obj3 подобен объекту, созданному // с помощью {} или new Object() var obj3 = Object.create(Object.prototype);

Возможность создавать новые объекты с произвольными прототипами (скажем иначе: возможность создавать «наследников» от любых объектов) является мощным инструментом, действие которого можно имитировать в ECMAScript 3 с помощью функции, представленной в примере ниже:

// inherit() возвращает вновь созданный объект, наследующий свойства // объекта-прототипа p. Использует функцию Object.create() из ECMAScript 5, // если она определена, иначе используется более старый прием. function inherit(p) { if (p == null) throw TypeError(); // p не может быть значением null if (Object.create) // Если Object.create() определена... return Object.create(p); // использовать ее. var t = typeof p; // Иначе выяснить тип и проверить его if (t !== "object" && t !== "function") throw TypeError(); function f() {}; // Определить пустой конструктор. f.prototype = p; // Записать в его свойство prototype // ссылку на объект p. return new f(); // Использовать f() для создания // "наследника" объекта p. }

Реализация функции inherit() приобретет больше смысла, как только мы познакомимся с конструкторами в следующей статье. А пока просто считайте, что она возвращает новый объект, наследующий свойства объекта в аргументе. Обратите внимание, что функция inherit() не является полноценной заменой для Object.create(): она не позволяет создавать объекты без прототипа и не принимает второй необязательный аргумент, как Object.create().

Получение и изменение свойств

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

// Простой объект var user = { login:"kot86", name:"Alexandr", age:26 }; var login = user.login; // Получить свойство "login" объекта user var name = user.name; // Получить свойство "name" объекта user var age = user["age"]; // Получить свойство "age" объекта user

Чтобы создать новое свойство или изменить значение существующего свойства, также используются операторы точки и квадратные скобки, как в операциях чтения значений свойств, но само выражение помещается уже слева от оператора присваивания:

User.age = 28; // Изменить значение свойства "age" user["login"] = "kot84"; // Изменить значение свойства "login" user["surname"] = "Frolov"; // Создать новое свойство "surname"

В ECMAScript 3 идентификатор, следующий за точкой, не может быть зарезервированным словом: нельзя записать обращение к свойству o.for или o.class, потому что for является ключевым словом, а class - словом, зарезервированным для использования в будущем.

Если объект имеет свойства, имена которых совпадают с зарезервированными словами, для доступа к ним необходимо использовать форму записи с квадратными скобками: o["for"] и o["class"]. Стандарт ECMAScript 5 ослабляет это требование (как это уже сделано в некоторых реализациях ECMAScript 3) и допускает возможность использования зарезервированных слов после оператора точки.

Прототипы

Каждый объект в языке JavaScript имеет второй объект (или null, но значительно реже), ассоциированный с ним. Этот второй объект называется прототипом, и первый объект наследует от прототипа его свойства.

Все объекты, созданные с помощью литералов объектов, имеют один и тот же объект-прототип, на который в программе JavaScript можно сослаться так: Object.prototype .

Объекты, созданные с помощью ключевого слова new и вызова конструктора, в качестве прототипа получают значение свойства prototype функции-конструктора. Поэтому объект, созданный выражением new Object(), наследует свойства объекта Object.prototype, как если бы он был создан с помощью литерала в фигурных скобках {}. Аналогично прототипом объекта, созданного выражением new Array(), является Array.prototype, а прототипом объекта, созданного выражением new Date(), является Date.prototype.

Object.prototype - один из немногих объектов, которые не имеют прототипа: у него нет унаследованных свойств. Другие объекты-прототипы являются самыми обычными объектами, имеющими собственные прототипы.

Все встроенные конструкторы (и большинство пользовательских конструкторов) наследуют прототип Object.prototype. Например, Date.prototype наследует свойства от Object.prototype, поэтому объект Date, созданный выражением new Date(), наследует свойства от обоих прототипов, Date.prototype и Object.prototype. Такая связанная последовательность объектов-прототипов называется цепочкой прототипов.

Наследование

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

Предположим, что программа обращается к свойству x объекта obj. Если объект obj не имеет собственного свойства с таким именем, выполняется попытка отыскать свойство x в прототипе объекта obj. Если объект-прототип не имеет собственного свойства с этим именем, но имеет свой прототип, выполняется попытка отыскать свойство в прототипе прототипа. Так продолжается до тех пор, пока не будет найдено свойство x или пока не будет достигнут объект, не имеющий прототипа. Как видите, атрибут prototype объекта создает цепочку, или связанный список объектов, от которых наследуются свойства.

Var obj = {}; // obj наследует методы объекта Object.prototype obj.x = 1; // и обладает собственным свойством x. var p = inherit(obj); // p наследует свойства объектов obj и Object.prototype p.y = 2; // и обладает собственным свойством y. var q = inherit(p); // q наследует свойства объектов p, obj и Object.prototype q.z = 3; // и обладает собственным свойством z. var s = q.toString(); // toString наследуется от Object.prototype var d = q.x + q.y // Результат 3: x и y наследуются от obj и p

Теперь предположим, что программа присваивает некоторое значение свойству x объекта obj. Если объект obj уже имеет собственное свойство (не унаследованное) с именем x, то операция присваивания просто изменит значение существующего свойства. В противном случае в объекте obj будет создано новое свойство с именем x. Если прежде объект obj наследовал свойство x, унаследованное свойство теперь окажется скрыто вновь созданным собственным свойством с тем же именем.

Операция присваивания значения свойству проверит наличие этого свойства в цепочке прототипов, чтобы убедиться в допустимости присваивания. Например, если объект obj наследует свойство x, доступное только для чтения, то присваивание выполняться не будет. Однако если присваивание допустимо, всегда создается или изменяется свойство в оригинальном объекте и никогда в цепочке прототипов. Тот факт, что механизм наследования действует при чтении свойств, но не действует при записи новых значений , является ключевой особенностью языка JavaScript, потому что она позволяет выборочно переопределять унаследованные свойства:

Var unitcircle = { r:1 }; // Объект, от которого наследуется свойство var c = inherit(unitcircle); // c наследует свойство r c.x = 1; c.y = 1; // c определяет два собственных свойства c.r = 2; // c переопределяет унаследованное свойство console.log(unitcircle.r); // => 1: объект-прототип не изменился

Существует одно исключение из этого правила, когда операция присваивания значения свойству терпит неудачу или приводит к созданию/изменению свойства оригинального объекта. Если объект obj наследует свойство x и доступ к этому свойству осуществляется посредством методов доступа, то вместо создания нового свойства x в объекте obj производится вызов метода записи нового значения. Однако обратите внимание, что метод записи вызывается относительно объекта obj, а не относительно прототипа, в котором определено это свойство, поэтому, если метод записи определяет какие-либо свойства, они будут созданы в объекте obj, а цепочка прототипов опять останется неизменной.

Ошибки доступа к свойствам

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

Попытка обращения к несуществующему свойству не считается ошибкой. Если свойство x не будет найдено среди собственных или унаследованных свойств объекта obj, выражение обращения к свойству obj.x вернет значение undefined.

Однако попытка обратиться к свойству несуществующего объекта считается ошибкой. Значения null и undefined не имеют свойств, и попытки обратиться к свойствам этих значений считаются ошибкой:

// Простой объект var user = { login:"kot86", name:"Alexandr", age:26 }; var a = user.password; // undefined: свойство отсутствует // Возбудит исключение TypeError. // Значение undefined не имеет свойства length var len = user.password.length;

Если нет уверенности, что user и user.password являются объектами (или ведут себя подобно объектам), нельзя использовать выражение user.password.length, так как оно может возбудить исключение. Ниже демонстрируются два способа защиты против исключений подобного рода:

// Более наглядный и прямолинейный способ var len = undefined; if (user) { if (user.password) len = user.password.length; } // Более краткая и характерная для JavaScript альтернатива // получения длины значения свойства password var len = user && user.password && user.password.length;

Попытки установить значение свойства для других значений не всегда оканчиваются успехом: некоторые свойства доступны только для чтения и не позволяют изменять их значения. Кроме того, некоторые объекты не позволяют добавлять в них новые свойства. Однако самое интересное, что подобные неудачи, как правило, не приводят к возбуждению исключения:

// Свойства prototype встроенных конструкторов доступны только для чтения Object.prototype = 0; // Присваивание не возбудит исключения; // значение Object.prototype не изменится

Этот исторически сложившийся недостаток JavaScript исправлен в строгом режиме, определяемом стандартом ECMAScript 5. Все неудачные попытки изменить значение свойства в строгом режиме приводят к исключению TypeError.

Правила, позволяющие определить, когда попытка выполнить операцию присваивания завершится успехом, а когда неудачей, просты и понятны, но их сложно выразить в достаточно краткой форме. Попытка присвоить значение свойству p объекта obj потерпит неудачу в следующих случаях:

    Объект obj имеет собственное свойство p, доступное только для чтения: нельзя изменить значение свойства, доступного только для чтения. (Обратите, однако, внимание на метод defineProperty(), который представляет собой исключение, позволяющее изменять значения настраиваемых свойств, доступных только для чтения.)

    Объект obj имеет унаследованное свойство p, доступное только для чтения: унаследованные свойства, доступные только для чтения, невозможно переопределить собственными свойствами с теми же именами.

    Объект obj не имеет собственного свойства p; объект obj не наследует свойство p с методами доступа и атрибут extensible объекта obj имеет значение false. Если свойство p отсутствует в объекте obj и для него не определен метод записи, то операция присваивания попытается добавить свойство p в объект obj. Но поскольку объект obj не допускает возможность расширения, то попытка добавить в него новое свойство потерпит неудачу.

Удаление свойств

Оператор delete удаляет свойство из объекта. Его единственный операнд должен быть выражением обращения к свойству. Может показаться удивительным, но оператор delete не оказывает влияния на значение свойства - он оперирует самим свойством:

// Простой объект var user = { login:"kot86", name:"Alexandr", age:26 }; delete user.login; // Теперь объект user не имеет свойства login delete user["name"]; // Теперь объект user не имеет свойства name

Оператор delete удаляет только собственные свойства и не удаляет унаследованные. (Чтобы удалить унаследованное свойство, необходимо удалять его в объекте-прототипе, в котором оно определено. Такая операция затронет все объекты, наследующие этот прототип.)

Выражение delete возвращает значение true в случае успешного удаления свойства или когда операция удаления не привела к изменению объекта (например, при попытке удалить несуществующее свойство). Выражение delete также возвращает true, когда этому оператору передается выражение, не являющееся выражением обращения к свойству:

Obj = {x:1}; // obj имеет собственное свойство x и наследует toString delete obj.x; // Удалит x и вернет true delete obj.x; // Ничего не сделает (x не существует) и вернет true delete obj.toString; // Ничего не сделает (toString не собственное свойство) и вернет true delete 1; // Бессмысленно, но вернет true

Оператор delete не удаляет ненастраиваемые свойства, атрибут configurable которых имеет значение false. (Однако он может удалять настраиваемые свойства нерасширяемых объектов.) Ненастраиваемыми являются свойства встроенных объектов, а также свойства глобального объекта, созданные с помощью инструкций объявления переменных и функций. Попытка удалить ненастраиваемое свойство в строгом режиме вызывает исключение TypeError. В нестрогом режиме (и в реализациях ECMAScript 3) в таких случаях оператор delete просто возвращает false:

Delete Object.prototype; // Удаление невозможно - ненастраиваемое свойство var x = 1; // Объявление глобальной переменной delete this.x; // Это свойство нельзя удалить function f() {} // Объявление глобальной функции delete this.f; // Это свойство также нельзя удалить

Проверка существования свойств

Объекты в языке JavaScript можно рассматривать как множества свойств, и нередко бывает полезно иметь возможность проверить принадлежность к множеству - проверить наличие в объекте свойства с данным именем. Выполнить такую проверку можно с помощью оператора in , с помощью методов hasOwnProperty() и propertyIsEnumerable() или просто обратившись к свойству.

Оператор in требует, чтобы в левом операнде ему было передано имя свойства (в виде строки) и объект в правом операнде. Он возвращает true, если объект имеет собственное или унаследованное свойство с этим именем:

Var obj = { x:1 } "x" in obj; // true: obj имеет собственное свойство "x" "y" in obj; // false: obj не имеет свойства "y" "toString" in obj; // true: obj наследует свойство toString

Метод hasOwnProperty() объекта проверяет, имеет ли объект собственное свойство с указанным именем. Для наследуемых свойств он возвращает false:

Var obj = { x:1 } obj.hasOwnProperty("x"); // true: obj имеет собственное свойство "x" obj.hasOwnProperty("y"); // false: obj не имеет свойства "y" obj.hasOwnProperty("toString"); // false: toString - наследуемое свойство

Метод propertyIsEnumerable() накладывает дополнительные ограничения по сравнению с hasOwnProperty(). Он возвращает true, только если указанное свойство является собственным свойством, атрибут enumerable которого имеет значение true. Свойства встроенных объектов не являются перечислимыми. Свойства, созданные обычной программой на языке JavaScript, являются перечислимыми, если не был использован один из методов ECMAScript 5, представленных ниже, которые делают свойства неперечислимыми.

Часто вместо оператора in достаточно использовать простое выражение обращения к свойству и использовать оператор!== для проверки на неравенство значению undefined:

Var obj = { x:1 } obj.x !== undefined; // true: obj имеет свойство "x" obj.y !== undefined; // false: obj не имеет свойства "y" obj.toString !== undefined; // true: obj наследует свойство toString

Однако оператор in отличает ситуации, которые неотличимы при использовании представленного выше приема на основе обращения к свойству. Оператор in отличает отсутствие свойства от свойства, имеющего значение undefined.

Перечисление свойств

Вместо проверки наличия отдельных свойств иногда бывает необходимо обойти все имеющиеся свойства или получить список всех свойств объекта. Обычно для этого используется цикл for/in, однако стандарт ECMAScript 5 предоставляет две удобные альтернативы.

Инструкция цикла for/in выполняет тело цикла для каждого перечислимого свойства (собственного или унаследованного) указанного объекта, присваивая имя свойства переменной цикла. Встроенные методы, наследуемые объектами, являются неперечислимыми, а свойства, добавляемые в объекты вашей программой, являются перечислимыми (если только не использовались функции, описываемые ниже, позволяющие сделать свойства неперечислимыми). Например:

// Простой объект с тремя перечислимыми свойствами var user = { login:"kot86", name:"Alexandr", age:26 }; user.propertyIsEnumerable("toString"); // false, toString - встроенный метод for (n in user) console.log(n);

Некоторые библиотеки добавляют новые методы (или другие свойства) в объект Object.prototype, чтобы они могли быть унаследованы и быть доступны всем объектам. Однако до появления стандарта ECMAScript 5 отсутствовала возможность сделать эти дополнительные методы неперечислимыми, поэтому они оказывались доступными для перечисления в циклах for/in. Чтобы решить эту проблему, может потребоваться фильтровать свойства, возвращаемые циклом for/in. Ниже приводятся два примера реализации такой фильтрации:

For (n in user) { if (!user.hasOwnProperty(n)) continue; console.log(n); } for (n in user) { if (typeof user[n] === "function") continue; console.log(n); }

В дополнение к циклу for/in стандарт ECMAScript 5 определяет две функции, перечисляющие имена свойств. Первая из них, Object.keys() , возвращает массив имен собственных перечислимых свойств объекта.

Вторая функция ECMAScript 5, выполняющая перечисление свойств - Object.getOwnPropertyNames() . Она действует подобно функции Object.keys(), но возвращает имена всех собственных свойств указанного объекта, а не только перечислимые. В реализациях ECMAScript 3 отсутствует возможность реализовать подобные функции, потому что ECMAScript 3 не предусматривает возможность получения неперечислимых свойств объекта.

Методы чтения и записи свойств

Выше уже говорилось, что свойство объекта имеет имя, значение и набор атрибутов. В ECMAScript 5 значение может замещаться одним или двумя методами, известными как методы чтения (getter) и записи (setter) . Свойства, для которых определяются методы чтения и записи, иногда называют свойствами с методами доступа , чтобы отличать их от свойств с данными, представляющих простое значение.

Когда программа пытается получить значение свойства с методами доступа, интерпретатор вызывает метод чтения (без аргументов). Возвращаемое этим методом значение становится значением выражения обращения к свойству. Когда программа пытается записать значение в свойство, интерпретатор вызывает метод записи, передавая ему значение, находящее справа от оператора присваивания. Этот метод отвечает за «установку» значения свойства. Значение, возвращаемое методом записи, игнорируется.

В отличие от свойств с данными, свойства с методами доступа не имеют атрибута writable. Если свойство имеет оба метода, чтения и записи, оно доступно для чтения/записи. Если свойство имеет только метод чтения, оно доступно только для чтения. А если свойство имеет только метод записи, оно доступно только для записи (такое невозможно для свойств с данными) и попытки прочитать значение такого свойства всегда будут возвращать undefined.

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

Var obj = { // Обычное свойство с данными data_prop: value, // Свойство с методами доступа определяется как пара функций get accessor_prop() { /* тело функции */ }, set accessor_prop(value) { /* тело функции */ } };

Свойства с методами доступа определяются как одна или две функции, имена которых совпадают с именем свойства и с заменой ключевого слова function на get и/или set.

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

Для примера рассмотрим следующий объект, представляющий декартовы координаты точки на плоскости. Для представления координат X и Y в нем имеются обычные свойства с данными, а также свойства с методами доступа, позволяющие получить эквивалентные полярные координаты точки:

Var p = { // x и y обычные свойства с данными, доступные для чтения/записи x: 1.0, y: 1.0, // r - доступное для чтения/записи свойство с двумя методами доступа. // Не забывайте добавлять запятые после методов доступа get r() { return Math.sqrt(this.x*this.x + this.y*this.y); }, set r(newvalue) { var oldvalue = Math.sqrt(this.x*this.x + this.y*this.y); var ratio = newvalue/oldvalue; this.x *= ratio; this.y *= ratio; }, // theta - доступное только для чтения свойство с единственным методом чтения get theta() { return Math.atan2(this.y, this.x); } };

Обратите внимание на использование ключевого слова this в методах чтения и записи выше. Интерпретатор будет вызывать эти функции, как методы объекта, в котором они определены, т.е. в теле функции this будет ссылаться на объект точки. Благодаря этому метод чтения свойства r может ссылаться на свойства x и y, как this.x и this.y.

Свойства с методами доступа наследуются так же, как обычные свойства с данными, поэтому объект p, определенный выше, можно использовать как прототип для других объектов точек. В новых объектах можно определять собственные свойства x и y, и они будут наследовать свойства r и theta.

Атрибуты объекта

Все объекты имеют атрибуты prototype, class и extensible. Все эти атрибуты описываются в подразделах ниже.

Атрибут prototype

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

Атрибут prototype устанавливается в момент создания объекта. Для объектов, созданных с помощью литералов, прототипом является Object.prototype. Прототипом объекта, созданного с помощью оператора new, является значение свойства prototype конструктора. А прототипом объекта, созданного с помощью Object.create(), становится первый аргумент этой функции (который может иметь значение null).

Стандартом ECMAScript 5 предусматривается возможность определить прототип любого объекта, если передать его методу Object.getPrototypeOf() . В ECMAScript 3 отсутствует эквивалентная функция, но зачастую определить прототип объекта obj можно с помощью выражения obj.constructor.prototype.

Объекты, созданные с помощью оператора new, обычно наследуют свойство constructor , ссылающееся на функцию-конструктор, использованную для создания объекта. И как уже говорилось выше, функции-конструкторы имеют свойство prototype, которое определяет прототип объектов, созданных с помощью этого конструктора.

Обратите внимание, что объекты, созданные с помощью литералов объектов или Object.create(), получают свойство constructor, ссылающееся на конструктор Object(). Таким образом, constructor.prototype ссылается на истинный прототип для литералов объектов, но обычно это не так для объектов, созданных вызовом Object.create().

Чтобы определить, является ли один объект прототипом (или звеном в цепочке прототипов) другого объекта, следует использовать метод isPrototypeOf() . Чтобы узнать, является ли p прототипом obj, нужно записать выражение p.isPrototypeOf(obj). Например:

Var p = {x:1}; // Определить объект-прототип. var obj = Object.create(p); // Создать объект с этим прототипом. p.isPrototypeOf(obj); // => true: obj наследует p Object.prototype.isPrototypeOf(p); // => true: p наследует Object.prototype

Атрибут class

Атрибут class объекта - это строка, содержащая информацию о типе объекта. Ни в ECMAScript 3, ни в ECMAScript 5 не предусматривается возможность изменения этого атрибута и предоставляются лишь косвенные способы определения его значения. По умолчанию метод toString() (наследуемый от Object.prototype) возвращает строку вида:

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

В примере ниже определяется функция, возвращающая класс любого объекта, переданного ей:

// Название класса объекта function classof(obj) { if (obj === null) return "Null"; if (obj === undefined) return "Undefined"; return Object.prototype.toString.call(obj).slice(8,-1); }

Этой функции classof() можно передать любое значение, допустимое в языке JavaScript. Числа, строки и логические значения действуют подобно объектам, когда относительно них вызывается метод toString(), а значения null и undefined обрабатываются особо.

Атрибут extensible

Атрибут extensible объекта определяет, допускается ли добавлять в объект новые свойства. В ECMAScript 3 все встроенные и определяемые пользователем объекты неявно допускали возможность расширения, а расширяемость объектов среды выполнения определялась каждой конкретной реализацией. В ECMAScript 5 все встроенные и определяемые пользователем объекты являются расширяемыми, если они не были преобразованы в нерасширяемые объекты, а расширяемость объектов среды выполнения по-прежнему определяется каждой конкретной реализацией.

Стандарт ECMAScript 5 определяет функции для получения и изменения признака расширяемости объекта. Чтобы определить, допускается ли расширять объект, его следует передать методу Object.isExtensible() . Чтобы сделать объект нерасширяемым, его нужно передать методу Object.preventExtensions() . Обратите внимание, что после того как объект будет сделан нерасширяемым, его нельзя снова сделать расширяемым. Отметьте также, что вызов preventExtensions() оказывает влияние только на расширяемость самого объекта. Если новые свойства добавить в прототип нерасширяемого объекта, нерасширяемый объект унаследует эти новые свойства.

Назначение атрибута extensible заключается в том, чтобы дать возможность «фиксировать» объекты в определенном состоянии, запретив внесение изменений. Атрибут объектов extensible часто используется совместно с атрибутами свойств configurable и writable, поэтому в ECMAScript 5 определяются функции, упрощающие одновременную установку этих атрибутов.

Метод Object.seal() действует подобно методу Object.preventExtensions(), но он не только делает объект нерасширяемым, но и делает все свойства этого объекта недоступными для настройки. То есть в объект нельзя будет добавить новые свойства, а существующие свойства нельзя будет удалить или настроить. Однако существующие свойства, доступные для записи, по-прежнему могут быть изменены.

После вызова Object.seal() объект нельзя будет вернуть в прежнее состояние. Чтобы определить, вызывался ли метод Object.seal() для объекта, можно вызвать метод Object.isSealed() .

Метод Object.freeze() обеспечивает еще более жесткую фиксацию объектов. Помимо того, что он делает объект нерасширяемым, а его свойства недоступными для настройки, он также делает все собственные свойства с данными доступными только для чтения. (Это не относится к свойствам объекта с методами доступа, обладающими методами записи; эти методы по-прежнему будут вызываться инструкциями присваивания.) Чтобы определить, вызывался ли метод Object.freeze() объекта, можно вызвать метод Object.isFrozen() .

Важно понимать, что Object.seal() и Object.freeze() воздействуют только на объект, который им передается: они не затрагивают прототип этого объекта. Если в программе потребуется полностью зафиксировать объект, вам, вероятно, потребуется зафиксировать также объекты в цепочке прототипов.

Сериализация объектов

Сериализация объектов - это процесс преобразования объектов в строковую форму представления, которая позднее может использоваться для их восстановления. Для сериализации и восстановления объектов JavaScript стандартом ECMAScript 5 предоставляются встроенные функции JSON.stringify() и JSON.parse() . Эти функции используют формат обмена данными JSON. Название JSON происходит от «JavaScript Object Notation» (форма записи объектов JavaScript), а синтаксис этой формы записи напоминает синтаксис литералов объектов и массивов в языке JavaScript:

Var obj = {x:1, y:{z:}}; // Определить испытательный объект var s = JSON.stringify(obj); // s == "{"x":1,"y":{"z":}}" var p = JSON.parse(s); // p - копия объекта obj

Синтаксис формата JSON является лишь подмножеством синтаксиса языка JavaScript и не может использоваться для представления всех возможных значений, допустимых в JavaScript. Поддерживаются и могут быть сериализованы и восстановлены: объекты, массивы, строки, конечные числовые значения, true, false и null. Значения NaN, Infinity и -Infinity сериализуются в значение null. Объекты Date сериализуются в строки с датами в формате ISO, но JSON.parse() оставляет их в строковом представлении и не восстанавливает первоначальные объекты Date.

Объекты Function, RegExp и Error и значение undefined не могут быть сериализованы или восстановлены. Функция JSON.stringify() сериализует только перечислимые собственные свойства объекта. Если значение свойства не может быть сериализовано, это свойство просто исключается из строкового представления. Обе функции, JSON.stringify() и JSON.parse(), принимают необязательный второй аргумент, который можно использовать для настройки процесса сериализации и/или восстановления, например, посредством определения списка свойств, подлежащих сериализации, или функции преобразования значений во время сериализации.

JavaScript является объектно-ориентированным языком . За исключением основных языковых конструкций типа циклов и операций отношения, почти все возможности JavaScript так или иначе реализованы с помощью объектов.

Иногда объекты используются явно для выполнения определенных задач, таких как, например, обработка документов (X)HTML и XML на основе объектной модели документа. В других случаях роль объектов менее очевидна, как, например, роль объекта String при работе с примитивными строковыми данными.

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

Объекты в JavaScript

Объекты в JavaScript можно поделить на четыре группы.

  • Пользовательские объекты, созданные программистом и имеющие структуру и сущность, которые соответствуют конкретной задаче программирования. Возможности создания и использования таких объектов мы обсудим в этой главе.
  • Встроенные объекты предлагаются самим языком JavaScript. Среди них объекты, связанные с типами данных (String, Number и Boolean), объекты, позволяющие создавать пользовательские объекты и составные типы (Object и Array), и объекты, упрощающие выполнение типичных задач (например, Date, Math и RegExp). Возможности встроенных объектов регламентированы стандартом языка ЕСМА-262 и, в меньшей степени, спецификациями производителей браузеров.
  • Объекты браузера, не являющиеся частью языка JavaScript, но поддерживаемые большинством браузеров. Примерами объектов браузера являются Window — объект, посредством которого осуществляется управление окнами браузера и взаимодействие с пользователем, и Navigator — объект, обеспечивающий информацию о конфигурации клиента. Поскольку большинство аспектов объектов браузера не регламентированы какими-либо стандартом, их свойства и поведение могут существенно зависеть как от браузера, так и от его версии. Объекты этого типа будут обсуждаться далее.
  • Объекты документа являются частью объектной модели документа (DOM — Document Object Model), определенной консорциумом W3C. Такие объекты предоставляют программисту структурированный интерфейс документов (X)HTML и XML. Именно эти объекты обеспечивают JavaScript возможность манипуляции вложенными таблицами стилей (CSS — Cascade Style Sheet) и упрощают реализацию динамического HTML (DHTML). Доступ к объектам документа обеспечивается браузером через свойство document объекта Window (window. document). Подробно о модели DOM мы поговорим позже.
  • Принципы работы с объектами

    Объект — это неупорядоченная совокупность данных, включающая примитивные типы данных, функции и даже другие объекты. Польза объектов заключается в том, -то они концентрируют в одном месте все данные и логику, необходимые для выполнения определенной конкретной задачи. Объект String хранит текстовые данные и предлагает множество функций, необходимых для действий с ними. Хотя присутствие объектов в языке программирования совсем не обязательно (в языке С, например, нет объектов), они определенно упрощают использование языка.

    Создание объектов

    Объект создается с помощью конструктора — функции специального вида, которая подготавливает новый объект для использования, инициализируя занимаемую Зъектом память. В главе 4 мы видели, что объекты можно создавать, применяя операцию new к их конструкторам. Применение этой операции заставляет конструктор создать новый объект, природа которого определяется вызываемым конструктором. Например, конструктор String () создает объекты String, а конструктор Array () — объекты Array. Именно так задаются имена объектных типов в JavaScript: по имени создающего объект конструктора.
    Вот простой пример создания объекта:

    var city = new String();

    Этот оператор создает новый объект String и размещает ссылку на него в переменной city. Здесь конструктору не предлагается никаких аргументов, поэтому переменная city получит значение по умолчанию — в данном случае это пустая строка. Можно сделать этот пример более интересным, передав конструктору аргумент, задающий начальное значение:

    var city = new String("Сан-Диего");

    Посещение веб-ресурса - это конкретный URI в адресной строке браузера. Посетитель указывает адрес страницы, и она разбирается браузером на элементы дерева DOM - Document Object Model. Любая ссылка на этой странице указывает браузеру разобрать другую страницу и построить иное дерево объектов.

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

    Фактически действия пользователя - это перемещение между системами объектов, образуемых в процессе посещения страниц. Каждая страница - это собственное дерево DOM и, помимо того, JavaScript object"s - это объекты синтаксиса самого языка и пользовательских описаний.

    DOM: загрузка, обновление и изменение

    Есть три основных варианта, которые формируют объекты страницы веб-ресурса, как на уровне DOM и самого языка JavaScript, выполнившего конструкции создания переменных, так и на основании описаний, сделанных разработчиком:

    • загрузка - посетитель пришел на страницу сайта;
    • обновление - посетитель (кнопка браузера или Ctrl-F5);
    • изменение элемента страницы, например (AJAX, скрипт, событие, ...).

    Все три процесса кардинально различаются, но отличать особенности первых двух особенно важно. Трудно запретить посетителю обновлять страницу - это неискоренимая «пагубная» привычка посетителя, которую разработчику следует иметь ввиду.

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

    Изменение страницы без перезагрузки на уровне отдельного её элемента (например, AJAX) - это обычное решение для динамичных страниц. Как правило, это используется для переходов по элементам страницы, изменения её объектов, управления диалогом с посетителем.

    Фундаментальные объекты JavaScript

    JavaScript основан на объектах. Практически все переменные языка - это объекты. Разработчик может формулировать собственные описания объектов, используя разнообразные варианты синтаксиса.

    Всё, не являющееся "строкой", "числом", true, false, null или undefined, является объектом. В рамках синтаксиса языка этому можно не придавать значения, понимая под объектами только элементы DOM и собственные описания JavaScript Object"s. Фундаментальное строение языка в большинстве случаев для разработчика не имеет существенного практического значения.

    Например, математические функции представлены объектом Math. Это удобно в рамках концепции языка, но для разработчика - это просто удобный синтаксис использования необходимого арсенала математических операций.

    Важно правильно работать с DOM и корректно описывать собственные объекты. Синтаксис JavaScript object function"s и выражений для их применения - это форма записи логики необходимого алгоритма.

    Строки, массивы и объекты

    В основе всех объектов JavaScript лежит правило: "свойство" = "значение" и понятие ассоциативного массива. В самом простом случае object JavaScript - это совокупность пар "свойство" = "значение". При этом "значение" не всегда может быть числом, а свойство не всегда записано без кавычек.

    Не следует злоупотреблять именованием свойств. Идеально, когда имена свойств содержат только символы латинского алфавита, удовлетворяют требованиям к именованию переменных и не являются ключевыми (в т. ч. зарезервированными) словами языка.

    Никакого упорядочивания свойств не предполагается, но при создании или инициализации ассоциативного массива знать, как расположены его элементы, вполне допустимо. Использовать это обстоятельство не рекомендуется, но иметь ввиду - возможно.

    Инициализировать массив свойств означает одновременно:

    • создание массива;
    • создание объекта.

    В конкретном контексте применения можно рассматривать JavaScript object - как ассоциативный массив, а в ином месте алгоритма - как объект, назначать ему нужные методы, изменять значения его элементов.

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

    Доступ к свойствам объекта

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

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

    Аналогичного эффекта можно достичь в точечной нотации или скобочной:

    • x1_Obj .NameLast;
    • x1_Obj ["NameFirst" ].

    Обе конструкции допустимы и дают нужный результат. В приведенном примере при задании массива через фигурные скобки "{}" может быть допущена ошибка в виде символа "," в конце перечисления (отмечено в примере красным кружочком). Обычно браузеры игнорируют лишний символ в перечислении, но лучше этого не делать.

    Удаление свойств объекта

    Поскольку объект - это ассоциативный массив, операция JavaScript delete object выполняется на уровне текущего объекта (при наследовании - это имеет значение) и рассматривается на коллекции свойств этого объекта.

    В контексте приведенного примера можно использовать такие конструкции:

    • delete x1_Obj .NameLast ;
    • delete x2_Obj ["NameFirst" ];

    Первая конструкция удаляет второй элемент первого объекта, вторая конструкция - первый элемент второго объекта. Оператор удаления не работает на свойствах прототипа и возвращает результатом значение false, если свойство не может быть удалено.

    Свойства и методы объектов

    Синтаксис JavaScript object properties и functions (методы) аналогичен общим канонам синтаксиса и семантики языка. По сути, дело обстоит как раз наоборот.

    Свойства и методы объекта - это вариант описания информации и допускаемых с нею действий через объектно-ориентированную парадигму JavaScript.

    В данном примере описан объект x3_Obj, у которого есть только два свойства: item и pos. Затем был добавлен метод hello() в виде функции. В результате интерпретацию этого описания в контексте значений свойств, JavaScript object values сделает так, как показано в окошке результата, то есть поместит тело функции (1) в качестве значения.

    При прямом вызове свойства Hello() оно интерпретируется как метод (функция) и результатом (2) будет исполнение кода этого метода.

    Ключевое слово this в объекте

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

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

    • var oCookie = new scCookies (cOwnerCode );
    • oCookie .Init ();

    В данном примере cOwnerCode - уникальный код посетителя. Если его нет, то в конструкторе объекта oCookie будет создан новый код. Неважно, что имел ввиду под авторизацией посетителя разработчик данного объекта, важно как ключевое слово this здесь используется для описания методов объекта и их вызова из других методов объекта:

    • this .GetCookie = function (cName) { ... };
    • this .SetCookie = function (cName, cValue) { ... }.

    Так описаны методы объекта для чтения куки по её имени и записи значения куки с конкретным именем.

    • this .GetCookie ("cOwner" );
    • this .SetCookie ("cOwner" , cOwner );

    Так они используются, если в результате первой конструкции значения не будет представлено, то вторая конструкция его устанавливает.

    Пример объекта для работы с куками

    Можно обсуждать, Object"s и парадигма объектно-ориентированного подхода языка, работающего в среде браузера. Это интересно, но в реальности нужна практика, а не теория. Обслуживать DOM страницы, предоставлять инструментарий для манипулирования объектами и перемещения по системам объектов - это сильная сторона JavaScript.

    На объектно-ориентированной практике важно другое. Работа с куками практически на всех веб-ресурсах в порядке вещей. Реализовать это в формате объекта - отличная идея. В этом контексте инициализация объекта происходит в момент открытия страницы: страница загружена = объект куки существует и всё прочитал, а чего не было - создал.

    В процессе работы со страницей посетитель совершает те или иные действия и браузер должен изменить или создать куки. Есть два метода объекта (обозначены выше), которые это делают.

    Фактически объект куки возникает сразу после того, как браузер построит DOM и дополняет систему объектов JavaScript новым функционалом: прочитать и создать (изменить) куки.

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

    При таком подходе разработчик обеспечивает создание системы уникальных объектов достаточных для описания и обслуживания решаемой задачи.

    События страницы и объектов

    Важный элемент функционирования DOM и JavaScript: object event"s - позволяющий получить информацию о событии в его обработчике. Практически каждому элементу страницы можно назначить собственный обработчик на одно или несколько событий.

    Фактически разработчик JavaScript создает не один большой «кусок» кода, а множество описаний функций, объектов, структур данных и назначает конкретным элементам страницы обработчики событий.

    Object event - это информация о событии, которое вызвало обработчик и возможность выполнения этим обработчиком адекватной реакции на это событие. Каждое событие отличается не только именем и местом возникновения, но и множеством других параметров.

    В частности, события клавиатуры - это один набор параметров, события мышки - совсем другой спектр данных, а ответ сервера через AJAX вовсе планирует сам разработчик.

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

    Создание и работа объектов

    Браузер "трансформирует" URI, адрес веб-ресурса, указанный посетителем, в дерево DOM - систему объектов страницы этого веб-ресурса. При перемещении посетителя по ссылкам страницы браузер переходит на соответствующие деревья других страниц.

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

    • работа с куками;
    • прием/передача данных (AJAX);
    • всплывающие подсказки;
    • внутренние сообщения (чат сайта);
    • другие задачи;

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

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

    JavaScript is designed on a simple object-based paradigm. An object is a collection of properties, and a property is an association between a name (or key ) and a value. A property"s value can be a function, in which case the property is known as a method. In addition to objects that are predefined in the browser, you can define your own objects. This chapter describes how to use objects, properties, functions, and methods, and how to create your own objects.

    Objects overview

    Objects in JavaScript, just as in many other programming languages, can be compared to objects in real life. The concept of objects in JavaScript can be understood with real life, tangible objects.

    In JavaScript, an object is a standalone entity, with properties and type. Compare it with a cup, for example. A cup is an object, with properties. A cup has a color, a design, weight, a material it is made of, etc. The same way, JavaScript objects can have properties, which define their characteristics.

    Objects and properties

    A JavaScript object has properties associated with it. A property of an object can be explained as a variable that is attached to the object. Object properties are basically the same as ordinary JavaScript variables, except for the attachment to objects. The properties of an object define the characteristics of the object. You access the properties of an object with a simple dot-notation:

    ObjectName.propertyName

    Like all JavaScript variables, both the object name (which could be a normal variable) and property name are case sensitive. You can define a property by assigning it a value. For example, let"s create an object named myCar and give it properties named make , model , and year as follows:

    Var myCar = new Object(); myCar.make = "Ford"; myCar.model = "Mustang"; myCar.year = 1969; myCar.color; // undefined

    Properties of JavaScript objects can also be accessed or set using a bracket notation (for more details see property accessors). Objects are sometimes called associative arrays , since each property is associated with a string value that can be used to access it. So, for example, you could access the properties of the myCar object as follows:

    MyCar["make"] = "Ford"; myCar["model"] = "Mustang"; myCar["year"] = 1969;

    An object property name can be any valid JavaScript string, or anything that can be converted to a string, including the empty string. However, any property name that is not a valid JavaScript identifier (for example, a property name that has a space or a hyphen, or that starts with a number) can only be accessed using the square bracket notation. This notation is also very useful when property names are to be dynamically determined (when the property name is not determined until runtime). Examples are as follows:

    // four variables are created and assigned in a single go, // separated by commas var myObj = new Object(), str = "myString", rand = Math.random(), obj = new Object(); myObj.type = "Dot syntax"; myObj["date created"] = "String with space"; myObj = "String value"; myObj = "Random Number"; myObj = "Object"; myObj[""] = "Even an empty string"; console.log(myObj);

    Please note that all keys in the square bracket notation are converted to string unless they"re Symbols, since JavaScript object property names (keys) can only be strings or Symbols (at some point, private names will also be added as the class fields proposal progresses, but you won"t use them with form). For example, in the above code, when the key obj is added to the myObj , JavaScript will call the obj.toString() method, and use this result string as the new key.

    You can also access properties by using a string value that is stored in a variable:

    Var propertyName = "make"; myCar = "Ford"; propertyName = "model"; myCar = "Mustang";

    Using a constructor function

    Alternatively, you can create an object with these two steps:

  • Define the object type by writing a constructor function. There is a strong convention, with good reason, to use a capital initial letter.
  • Create an instance of the object with new .
  • To define an object type, create a function for the object type that specifies its name, properties, and methods. For example, suppose you want to create an object type for cars. You want this type of object to be called Car , and you want it to have properties for make, model, and year. To do this, you would write the following function:

    Function Car(make, model, year) { this.make = make; this.model = model; this.year = year; }

    Notice the use of this to assign values to the object"s properties based on the values passed to the function.

    Now you can create an object called mycar as follows:

    Var mycar = new Car("Eagle", "Talon TSi", 1993);

    This statement creates mycar and assigns it the specified values for its properties. Then the value of mycar.make is the string "Eagle", mycar.year is the integer 1993, and so on.

    You can create any number of Car objects by calls to new . For example,

    Var kenscar = new Car("Nissan", "300ZX", 1992); var vpgscar = new Car("Mazda", "Miata", 1990);

    An object can have a property that is itself another object. For example, suppose you define an object called person as follows:

    Function Person(name, age, sex) { this.name = name; this.age = age; this.sex = sex; }

    and then instantiate two new person objects as follows:

    Var rand = new Person("Rand McKinnon", 33, "M"); var ken = new Person("Ken Jones", 39, "M");

    Then, you can rewrite the definition of Car to include an owner property that takes a person object, as follows:

    Function Car(make, model, year, owner) { this.make = make; this.model = model; this.year = year; this.owner = owner; }

    To instantiate the new objects, you then use the following:

    Var car1 = new Car("Eagle", "Talon TSi", 1993, rand); var car2 = new Car("Nissan", "300ZX", 1992, ken);

    Notice that instead of passing a literal string or integer value when creating the new objects, the above statements pass the objects rand and ken as the arguments for the owners. Then if you want to find out the name of the owner of car2, you can access the following property:

    Car2.owner.name

    Note that you can always add a property to a previously defined object. For example, the statement

    Car1.color = "black";

    adds a property color to car1, and assigns it a value of "black." However, this does not affect any other objects. To add the new property to all objects of the same type, you have to add the property to the definition of the Car object type.

    Using the Object.create method See also
    • To dive deeper, read about the details of javaScript"s objects model .
    • To learn about ECMAScript 2015 classes (a new way to create objects), read the JavaScript classes chapter.

    Условие задачи :

    1. Есть три объекта (три автомобиля) : first_Car , second_Car и third_Car .

    2. Каждый из объектов (автомобилей) имеет набор свойств и соответствующих им значений (характеристики автомобиля ).

    3. Рассмотрим один из объектов:

    var first_Car = {
    make: "VAZ" , /* производитель */
    model: 2106 , /* модель */
    year: 1980 , /* год выпуска */
    color: "beige" , /* цвет */
    passengers: 5 , /* число пассажиров */
    convertible: false, /* откидной верх */
    mileage: 80000 /* пробег */
    }

    Свойства make и color имеют строковые значения;

    Свойства model , year , passengers и mileage - числовые значения;

    Свойство convertible принимает булево значение.

    Нужно сделать следующее :

    Написать функцию, которая проверяет автомобиль по двум параметрам (год выпуска и пробег) и возвращает булево значение true или false .

    Подробности :

    1. Функция имеет один параметр car , в качестве которого получает один из 3-х объектов. Например, выше рассмотренный автомобиль first_Car .

    2. Функция должна работать с любым подобным объектом.

    Функция для проверки объекта - true или false

    /* 1-ый объект */
    var first_Car = {
    make: "VAZ",
    model: 2106,
    year: 1980 ,
    color: "beige",
    passengers: 5,
    convertible: false,
    mileage: 80000
    }

    /* 2-ой объект */
    var second_Car = {
    make: "VW",
    model: "Passat b3",
    year: 1990 ,
    color: "neptune",
    passengers: 5,
    convertible: false,
    mileage: 160000
    }

    /* 3-ий объект */
    var third_Car = {
    make: "Hyundai",
    model: "Solaris",
    year: 2012 ,
    color: "wet asphalt",
    passengers: 5,
    convertible: false,
    mileage: 15000
    }


    function good_Car(car) {
    if (car. year < 2000 ){
    return false;
    }
    else if (car. mileage > 50000 ){
    return false;
    }
    else{
    return true;
    }
    }

    /* Вызов функции и Вывод результата */
    var result = good_Car ( third_Car );

    document . write ( result );

    Комментарии к решению:

    • Итак, мы имеем три объекта (три автомобиля) , каждый из которых можно проанализировать при помощи функции good_Car .
    • Функция good_Car имеет один параметр car , в качестве которого может выступать любой из объектов (автомобилей) : first_Car , second_Car или third_Car : function good_Car(car) .
    • В теле Функции good_Car составлено условие, согласно которому:

      Если значение свойства year объекта car меньше 2000 (другими словами : если год выпуска автомобиля меньше 2 000) , то функция возвращает false;

      Иначе, если значение свойства mileage объекта car больше 50000 (если пробег автомобиля больше 50 000) , то функция возвращает false;

      Иначе функция возвращает true .

    • Далее мы вызываем функцию и в качестве параметра указываем объект third_Car (третий автомобиль) , который успешно проходит проверку. Результат работы функции заносится в переменную result :
      var result = good_Car(third_Car); .
    • Переменная result выводится на экран;
    • Два других объекта (автомобиля) не будут соответствовать требованиям условия.
    Оптимизация кода

    Продолжим работать с объектами в javascript .

    Итак, рассмотренная выше функция при проверке объектов (автомобилей) выдает в результате true или false (истину или ложь) .

    Можно немного улучшить качество восприятия решения рассмотренной задачи, то есть вместо true или false выводить какой-либо текст. Для этого составим условие для анализа результата.

    /* 1-ый объект */
    var first_Car = {
    make: "VAZ",
    model: 2106,
    year: 1980 ,
    color: "beige",
    passengers: 5,
    convertible: false,
    mileage: 80000
    }

    /* 2-ой объект */
    var second_Car = {
    make: "VW",
    model: "Passat b3",
    year: 1990 ,
    color: "neptune",
    passengers: 5,
    convertible: false,
    mileage: 160000
    }

    /* 3-ий объект */
    var third_Car = {
    make: "Hyundai",
    model: "Solaris",
    year: 2012 ,
    color: "wet asphalt",
    passengers: 5,
    convertible: false,
    mileage: 15000
    }

    /* Функция для проверки объекта */
    function good_Car(car) {
    if (car. year < 2000 ){
    return false;
    }
    else if (car. mileage > 50000 ){
    return false;
    }
    else{
    return true;
    }
    }


    var result = good_Car ( third_Car );

    if(result) {
    document . write ("У Вас неплохой автомобиль: " + third_Car . year + " год выпуска, с пробегом " + third_Car .mileage + " км." );
    }
    else{
    document . write ("Не будем говорить о Вашем автомобиле...." );
    }

    Решение с условием для результата - Результат...

    Условие для анализа результата составлено следующим образом.

    • Выражение if(result) является сокращенной формой записи выражения
      if(result == true) .
    • Если результат работы функции good_Car является истинным true , то мы выводим на экран фразу: «У Вас неплохой автомобиль: 2012 год выпуска, с пробегом 15000 км.», где

      2012 и 15000 - это значения свойств year и mileage объекта third_Car .

    • Если же условие для проверки результата выдаст ложное значение false , то мы увидим: «Не будем говорить о Вашем автомобиле....». То есть рассматриваемый объект (автомобиль) не прошел проверку.
    Оптимизация кода - Идем дальше - Добавляем функцию

    Но и это еще не все. Посмотрите внимательно на фрагмент кода для вызова функции и анализа результата:

    /* Вызов функции и Анализ результата */
    var result = good_Car( third_Car );

    if(result) {
    document.write("У Вас неплохой автомобиль: " + third_Car .year + " год выпуска, с пробегом " + third_Car .mileage + " км.");
    }
    else{
    document.write("Не будем говорить о Вашем автомобиле....");
    }

    Здесь объект third_Car (третий автомобиль) указывается трижды:

    • Первый раз при вызове функции good_Car он указан в качестве ее параметра: good_Car(third_Car) .
    • И далее он фигурирует еще дважды, когда мы к нему обращаемся для указания его свойств: third_Car.year и third_Car.mileage .

    Мне это не понравилось, так как при анализе другого объекта (автомобиля) нам придется его имя также указывать трижды !!!

    Чтобы добиться одноразового указания анализируемого объекта, нужно и результат работы функции good_Car и анализ этого результата (то есть весь ) занести в еще одну функцию.

    /* 1-ый объект */
    var first_Car = {
    make: "VAZ",
    model: 2106,
    year: 1980 ,
    color: "beige",
    passengers: 5,
    convertible: false,
    mileage: 80000
    }

    /* 2-ой объект */
    var second_Car = {
    make: "VW",
    model: "Passat b3",
    year: 1990 ,
    color: "neptune",
    passengers: 5,
    convertible: false,
    mileage: 160000
    }

    /* 3-ий объект */
    var third_Car = {
    make: "Hyundai",
    model: "Solaris",
    year: 2012 ,
    color: "wet asphalt",
    passengers: 5,
    convertible: false,
    mileage: 15000
    }

    /* Функция для проверки объекта */
    function good_Car(car ) {
    if (car .year < 2000){
    return false;
    }
    else if (car .mileage > 50000){
    return false;
    }
    else{
    return true;
    }
    }

    /* Заносим результат работы функции good_Car и Анализ результата в еще одну функцию */
    function itog(car ){
    var result = good_Car(car );

    If(result ) {
    document.write("У Вас неплохой автомобиль: " + car .year + " год выпуска, с пробегом " + car .mileage + " км.");
    }
    else{
    document.write("Не будем говорить о Вашем автомобиле....");
    }
    }

    itog( third_Car );

    Решение с использованием еще одной функции - Результат...

    У Вас неплохой автомобиль: 2012 год выпуска, с пробегом 15000 км.