JavaScript спроектирован на основе простой парадигмы. В основе концепции лежат простые объекты. Объект - это набор свойств, и свойство состоит из имени и значения, ассоциированного и этим именем. Значением свойства может быть функция, которую можно назвать методом объекта. В дополнение к встроенным в браузер объектам, вы можете определить свои собственные объекты. Эта глава описывает как пользоваться объектами, свойствами, функциями и методами, а также как создавать свои собственные объекты.
Обзор объектов
Объекты в JavaScript, как и во многих других языках программирования, похожи на объекты реальной жизни. Концепцию объектов JavaScript легче понять, проводя паралелли с реально существующими в жизни объектами.
В JavaScript, объект это самостоятельная единица, имеющая свойства и определенный тип. Сравним, например, с чашкой. У чашки есть цвет, форма, вес, материал, из которого она сделана, и т.д. Точно так же, объекты JavaScript имеют свойства, которые определяют их характеристики.
Объекты и свойства
В JavaScript объект имеет свойства, ассоциированные с ним. Свойство объекта можно понимать как переменную, закрепленную за объектом. Свойства объекта в сущности являются теми же самыми переменными JavaScript, за тем исключением, что они закреплены за объектом. Свойства объекта определяют его характеристики. Получить доступ к свойству объекта можно так:
objectName.propertyName
Как и все переменные JavaScript, имя объекта (которое тоже может быть переменной) и имя свойства являются чуствительными к регистру. Вы определяете свойство, просто указывая его значение. Например, давайте созданим объект myCar
и определим его свойства make
, model
, и year
следующим образом:
var myCar = new Object(); myCar.make = "Ford"; myCar.model = "Mustang"; myCar.year = 1969;
Доступ к свойствам объектов JavaScript можно получить через квадратные скобки. Объекты являются, ассоциативными массивами, так как каждое свойство ассоциировано с именем, через которое можно получить доступ к нему. Например, доступ к свойствам объекта myCar
можно получить след.образом:
myCar["make"] = "Ford"; myCar["model"] = "Mustang"; myCar["year"] = 1969;
Имена свойств объекта могут быть строками JavaScript, или тем, что может быть сконвертировано в строку, включая пустую строку. Как бы то ни было, доступ к любому имени свойства, которое содержит невалидный JavaScript идентификатор (например, имя свойства содержит в себе пробел и тире или начинается с цифры), может быть получен с использование квадратных скобок. Этот способ также полезен в случае если имена свойств определяются динамически в процессе выполнения скрипта. Примеры далее:
var myObj = new Object(), str = "myString", rand = Math.random(), obj = new Object(); myObj.type = "Dot syntax"; myObj["date created"] = "String with space"; myObj[str] = "String value"; myObj[rand] = "Random Number"; myObj[obj] = "Object"; myObj[""] = "Even an empty string"; console.log(myObj);
Вы также можете получить доступ к свойству, воспользовавшись строковой переменной в которой хранится имя свойства:
var propertyName = "make"; myCar[propertyName] = "Ford"; propertyName = "model"; myCar[propertyName] = "Mustang";
Вы можете пользоваться квадратными скобками в конструкции for...in чтобы выполнить итерацию всех свойств объекта, для которых она разрешена. Чтобы показать как это работает, следующая функция показывает все свойства объекта, когда вы передаете в нее сам объект и его имя как аргументы функции:
function showProps(obj, objName) { var result = ""; for (var i in obj) { if (obj.hasOwnProperty(i)) { result += objName + "." + i + " = " + obj[i] + "\n"; } } return result; }
Так что, если вызвать эту функцию вот так showProps(myCar, "myCar")
то получим результат:
myCar.make = Ford myCar.model = Mustang myCar.year = 1969
Все в JavaScript это объект
В JavaScript почти все является объектом. Все примитивные типы за исключением null
и undefined
обрабатываются как объекты. Они могут быть назначены свойствам, и у них есть все характеристики, присущие объектам.
Перечисление всех свойств объекта
Начиная с ECMAScript 5, есть три способа перечислить все свойства (или получить список из онных) объекта:
- циклы for...in
Этот медот перебирает все перечисляемые свойства объекта и его цепочки прототипов - Object.keys(o)
Этот метод возвращает массив со всеми собственными (те что цепочке прототипов не войдут в массив) именами перечисляемых свойств объектаo
. - Object.getOwnPropertyNames(o)
Этот метод возвращает массив содержащий все имена своих свойств (перечисляемых и не) объектаo
.
В ECMAScript 5 нет родного способа перечислить сами свойства объекта. Но это можно сделать с помощью след. функции:
function listAllProperties(o){ var objectToInspect; var result = []; for(objectToInspect = o; objectToInspect !== null; objectToInspect = Object.getPrototypeOf(objectToInspect)){ result = result.concat(Object.getOwnPropertyNames(objectToInspect)); } return result; }
Это может быть полезно для обнаружения скрытых (hidden) свойств (свойства в цепочке прототипа, которые недоступны через объект, так как другое свойство имеет такое имя в предыдущем звене из цепочки прототипа). Перечислить доступные свойства можно, если удалить дубликаты из массива.
Создание новых объектов
JavaScript содержит набор встроеных объектов. Также вы можете создавать свои объекты. Начиная с JavaScript 1.2, вы можете создавать объект с помощью инициальзатора объекта. Другой способ -- создать функцию-конструктор и сделать экземпляр объекта с помощью этой функции и оператора new
.
Использование инициализаторов объекта
Помимо создания объектов с помощью функции конструктора, вы можете создавать объекты и другим, особым способом. Фактически вы можете записать объект синтаксически, и он будет создан интерпретатором автоматически во время выполнения. Эта синтаксическая схема приведена ниже:
var obj = { property_1: value_1, // property_# may be an identifier... 2: value_2, // or a number... // ..., "property n": value_n }; // or a string
здесь obj
это имя нового объекта, каждое property_i
это идентификатор (имя, число или строковый литерал), и каждый value_i
это значения, назначенные property_i
. Имя obj
и ссылка объекта на него необязательна; если далее вам не надо будет ссылаться на данный объект, то вам не обязательно назначать объект переменной. (Обратите внимание, что вам потребуется обернуть литерал объекта в скобки, если объект находится в месте, где ожидается инструкция, чтобы интерпретатор не перепутал его с блоком.)
Если объект создан при помощи инициализатора объектов на высшем уровне скрипта, то JavaScript интерпретирует объект каждый раз, когда анализирует выражение, содержащее объект записанный как литерал. Плюс, если пользоваться функцией инициализатором, то он будет создается каждый раз, когда функция вызывается.
Следующая инструкция создает объект и назначает его переменной x
, когда выражение cond
истинно.
if (cond) var x = {hi: "there"};
След. пример создает объект myHonda
с тремя свойствами. Заметьте, что свойство engine
- это также объект со своими собственными свойствами.
var myHonda = { color: "red", wheels: 4, engine: { cylinders: 4, size: 2.2 } };
Вы также можете использовать инициализатор объекта для создания массивов. Смотрите array literals.
До JavaScript 1.1 не было возможности пользоваться инициализаторами объекта. Единственный способ создавать объекты -- это пользоваться функциями-конструкторами или функциями других объектов, предназначенных для этой цели. Смотрите Using a constructor function.
Использование функции конструктора
Другой способ создать объект в два шага описан ниже:
- Определите объект, набрав функцию-конструктор. Название такой функции, как правило, начинается с заглавной буквы.
- Создайте экземпляр объекта с помощью ключевого слова
new
.
Чтобы определить тип объекта, создайте функцию для которая определяет тип объекта, его имя, свойства и методы. Наример положим вы хотите создать тип объект для cars.Вы хотите чтобы объект этого типа назывался car
, и вы хотите чтобы у него были свойства make, model, и year. Чтобы сделать это, напишите след. функцию:
function Car(make, model, year) { this.make = make; this.model = model; this.year = year; }
Заметьте, что используется this
чтобы назначить значения (переданные как аргументы функции) свойствам объекта.
Теперь вы можете создать объект нызваемый mycar
след. образом:
var mycar = new Car("Eagle", "Talon TSi", 1993);
Эта инструкция создает объект типа Car с ссылкой mycar
и назначает определенные значения его свойствам. Значение mycar.make
строка "Eagle", mycar.year
это целое число 1993, и так далее.
Вы можете создать столько объектов car
сколько нужно просто вызывая new
. Например,
var kenscar = new Car("Nissan", "300ZX", 1992); var vpgscar = new Car("Mazda", "Miata", 1990);
Объект может иметь свойтво которое будет другим объектом. Например, далее определяет объект типа Pe
rson
след. образом:
function Person(name, age, sex) { this.name = name; this.age = age; this.sex = sex; }
и затем создать два новых экземпляря объектов person
как показано далее:
var rand = new Person("Rand McKinnon", 33, "M"); var ken = new Person("Ken Jones", 39, "M");
Затем, вы можете переписать определение car
и включить в него свойство owner
которому назначить объект person
след. образом:
function Car(make, model, year, owner) { this.make = make; this.model = model; this.year = year; this.owner = owner; }
Затем, чтобы создать экземпляры новых объектов, выполните след. инструкции:
var car1 = new Car("Eagle", "Talon TSi", 1993, rand); var car2 = new Car("Nissan", "300ZX", 1992, ken);
Замечание. Вместо того чтобы передавать строку литерал или целое число когда создаются новые объекты, в выражениях выше передаются объекты rand
и ken
как аргумент функции. Затем если вам нужно узнать имя владельца car2, это можно узнать след. образом:
car2.owner.name
Заметьте что вы всегда можете добавить свойство после создания объекта. Например, выражение
car1.color = "black";
добавляет свойство color
к car1, и устанавливаего его значение равным "black." Как бы там ни было, это не влияет на любые другие объекты. Чтобы добавить новое свойство всем объектам одного типа, вы должны добавить свойство в определения типа объекта car
.
Использование метода Object.create
Объекты также можно создавать с помощью метода Object.create
. Этот метод очень удобный, так как позволяет вам указывать объект прототип для нового вашего объекта, без определения функции конструктора. Больше информации об этом методе и том как им пользоваться, смотрите Object.create method
Наследование
Все объекты в JavaScript наследуются как минимум от одного другого объекта. Объект от которого произошло наследование назвается прототипом, и унаследованные свойства могут быть найдены в объекте prototype
конструктора.
Индексы свойств объекта
В JavaScript 1.0, вы можете сослаться на свойства объекта либо по его имени либо по его порядковому индексу. В JavaScript 1.1 и позже, если изначально определили свойство по имени, вы всегда должны ссылаться на него по его имени, и если вы изначально определили свойство по индексу, вы должны ссылаться на него по его индексу..
Это ограничение налагается когда вы создаете объект и его свойства с помощью функции конструктора (как мы это делали ранее с типом Car ) и когда вы определяете индивидуальные свойства явно (например, myCar.color = "red"
). Если вы изначально определили свойство объекта через индекс, например myCar[5] = "25 mpg"
, то впоследствии сослаться на это свойство можно только так myCar[5]
.
Исключение из правил объекты из HTML, например массив forms
. Вы всегда можете сослаться на объекты в этих массивах или используя их индекс (который основывается на порядке появления в HTML документе) или на их именах (если таковые были определены). Например, если второй html тег <FORM>
в документе имеет значение аттрибута NAME
равное "myForm", вы можете сослаться на эту форму вот так document.forms[1]
или document.forms["myForm"]
или document.myForm
.
Определение свойств для типа объекта
Вы можете добавить свойство к ранее определенному типу объекта воспользовавшись свойством prototype
. Это определяет свойство которое единое для всего объектов определенного типа, а не одного экземпляря этого типа объекта. След. код демонстрирует это добавляя свойство color
ко всем объектам типа car
,и замет присваивая значение значение свойству color
объекта car1
.
Car.prototype.color = null; car1.color = "black";
Смотри
prototype
property объекта Function
в Справочнике JavaScript для получения деталей.
Определение методов
Метод это функция ассоциированная с объектом или проще говоря метод это свойство объекта являющееся функцией. Методы определяются так же как и обычные функции, за тем исключением что они присваиваются свойству объекта. Например вот так:
objectName.methodname = function_name; var myObj = { myMethod: function(params) { // ...do something } };
где objectName
это существующий объект, methodname
это имя которое вы присваиваете методу, и function_name
это имя самой функции.
Затме вы можете вызвать метод в контексте объекта след. образом:
object.methodname(params);
Вы можете определять методы для объекта типа включая определения метода в фукцию конструктора объекта. Например, вы можете определить функцию которая форматирует и отображет свойства до этого определенных объектов car
; например,
function displayCar() { var result = "A Beautiful " + this.year + " " + this.make + " " + this.model; pretty_print(result); }
где pretty_print
это функция отображения горизонтальной линии и строки. Заметьте, что использование this
позволяет ссылаться на объект к которому принадлежит метод.
Вы можете сделать эту функцию методом car
добавив инструкцию
this.displayCar = displayCar;
к определению объекта. Так что полное определение car
выглядит теперь след.образом
function Car(make, model, year, owner) { this.make = make; this.model = model; this.year = year; this.owner = owner; this.displayCar = displayCar; }
Затем вы можете вызвать метод displayCar
для каждого из объектов след. образом:
car1.displayCar(); car2.displayCar();
Вывод этих выражений показан на рисунке ниже.
Figure 7.1: Displaying method output.
Использование this
для ссылки на объект
В JavaScript есть специальное слово, this
, которое вы можете использовать внутри метода чтобы ссылаться на текущий объект. Предположим у вас есть функция, называемая validate,
которая сверяет свойство объекта value
, переданного ей с некоторыми верхним и нижним переданными значениями:
function validate(obj, lowval, hival) { if ((obj.value < lowval) || (obj.value > hival)) alert("Invalid Value!"); }
Когда вы вызываете validate
в каждой из форм в обработчике события onchange
, используйте this
чтобы передать этот элемент, как это сделано ниже:
<input type="text" name="age" size="3" onChange="validate(this, 18, 99)">
В общем, this
ссылается на объект вызвавший метод.
В сечетании со свойством form
, this
ссылается на родительскую форму текущего объекта. В след. примере, форма myForm
содержит объект Text
и кнопку. Когда пользователь нажимает кнопку, значение объекта Text
назначается имя формы. Обработчик событий кнопки onclick
пользуется this.form
чтобы сослаться на текущую форму, myForm
.
<form name="myForm"> <p><label>Form name:<input type="text" name="text1" value="Beluga"></label> <p><input name="button1" type="button" value="Show Form Name" onclick="this.form.text1.value = this.form.name"> </p> </form>
Определение геттеров и сеттеров
Геттер (от англ. get получить) это метод которые получает значениме определенного свойства. Сеттер (от англ. set - присвоить) это метод который присваивает значение определенному свойству объекта. Вы можете определить геттеры и сеттеры для любых из встроенных или вами определенных объектов которые поддерживают добавление новых свойств. Синтаксис определения геттеров и сеттеров пользуется синтаксисом литеральных объектов.
JavaScript 1.8.1 замечание
Starting in JavaScript 1.8.1, setters are no longer called when setting properties in object and array initializers.
Следующая сессия в JS шеле иллюстрирует как геттеры и сеттеры работают с объектом o
определенным пользователем. JS шелл это приложение которое позволяет разработчику тестировать код JavaScript интерактивно или выполнить группу инструкций.
js> var o = {a: 7, get b() {return this.a + 1;}, set c(x) {this.a = x / 2}}; [object Object] js> o.a; 7 js> o.b; 8 js> o.c = 50; js> o.a; 25
Свойства объекта o
это:
o.a
— числоo.b
— геттер который возвращаетo.a
плюс 1o.c
— сеттер который присваивает значениеo.a
половине значения которое переданоo.c
Заметьте, что имена функций геттера и сеттера определны в литерале объекта используя "[gs]et property()" (в отличии от __define[GS]etter__
ниже) не являются именами самих геттеров, хотя синтаксис [gs]et propertyName(){ }
может ввести вас в заблуждение. Для именования функции геттера или сеттера использущьх синтаксис "[gs]et property()", определите явно имена функций программно, используя Object.defineProperty
(или Object.prototype.__defineGetter__ при наследовании
).
Данная JavaScript shell сессия показывает как геттер и сеттер могут расширить прототип класса Date добавлением свойства year
во все экземпляры переопределеннго класса Date
. Используются существующие в классе Date
методы getFullYear
и setFullYear
для добавления геттера и сеттера свойства year.
Данный код определяет геттер и сеттер для свойства year:
js> var d = Date.prototype; js> d.__defineGetter__("year", function() { return this.getFullYear(); }); js> d.__defineSetter__("year", function(y) { this.setFullYear(y); });
Данный код использует геттер и сеттер объекта Date
:
js> var now = new Date; js> print(now.year); 2000 js> now.year = 2001; 987617605170 js> print(now); Wed Apr 18 11:13:25 GMT-0700 (Pacific Daylight Time) 2001
Устаревший синтаксис
В прошлом, JavaScript поддерживал несколько других синтаксических конструкций для определения геттеров и сеттеров. Заметьте что этот синтаксис поддрерживались и другими движками, и подддрежка была удалена в последних версиях JavaScript. Смотрите здесь подробное описание удаленного синтаксиса что именно удалено и как адаптироваться код.
Заключение
В принципе, геттеры и сеттеры могут быть:
- определены с использованием инициализатор объекта, или
- добавлены позже в любые объекты и в любое время методы добавления геттеров или сеттеров.
Когда геттеры и сеттеры определяются с использованием инициализаторов объекта всё что вам нужно сделать, добвить префекс get для геттера и префикс set для сеттера. И конечно, геттер не должен ожидать получения параметров, в то время как сеттер получает ровно один параметр (для установки новго значения). Например:
var o = { a: 7, get b() { return this.a + 1; }, set c(x) { this.a = x / 2; } };
Геттеры и сеттеры могут быть добавлены к объекту в любое время после его создания с помощью метода Object.defineProperties. Этот метод первым параметром принимает объект, которому требуется назначить геттер и/или сеттер, а вторым объект, содержащий методы геттера и/или сеттера. См. ниже пример определения некоторых геттера и сеттера использованных так же в предыдущем примере:
var o = { a:0 };
Object.defineProperties(o, {
"b": { get: function () { return this.a + 1; } },
"c": { set: function (x) { this.a = x / 2; } }
});
o.c = 10 // Вызывает сеттер, который присваивает 10 / 2 свойству a
console.log(o.b) // Вызывает геттер, который
возвращает a + 1 (6)
Того же можно добиться с помощью двух специальных методов: __defineGetter__,
__defineSetter__
. Каждый из этих методов принимает два параметра: имя свойства и функция вызываемая геттером / сеттером. См пример ниже (продолжение предыдущего примера):
o.__defineGetter__("b", function() { return this.a + 1; }); o.__defineSetter__("c", function(x) { this.a = x / 2; });
Однако, эти методы устарели и не рекомендуются к дальнейшему использованию.
Какую из этих двух форм записи выбрать зависит от вашего стиля программирования и конкретной задачи. Если вы определяете объект с помощью инициализатора {},
то вам, возможно, будет удобнее воспользоваться первой формой. Такая запись будет более естсетвенной и компактной. Однако, если геттеры/сеттеры требуется добавить позднее — потому что вы не определяете прототип или отдельный объект — то вторая форма будет единственно возможной. Она, возможно, лучшая демонстрация динамической природы JavaScript — но, в то же время, она может сделать код более тяжело воспринимаемым человеком.
До Firefox 3.0, геттеры и сеттеры не поддерживались для элементов DOM. Старые версии Firefox просто игнорируют это выражение. Если требуется исключение в этих случаях, изменение прототипа HTMLElement (HTMLElement.prototype.__define[SG]etter__)
и выброс исключения как костыли для этого решения.
Смотрите также
__defineGetter__ (deprecated)
__defineSetter__ (deprecated)
get
set
- Object.defineProperty [ru]
Удаление свойств
Вы можете удалить свойство используя оператор delete
. След. код прказывает как удалить свойство.
//Creates a new object, myobj, with two properties, a and b. var myobj = new Object; myobj.a = 5; myobj.b = 12; //Removes the a property, leaving myobj with only the b property. delete myobj.a;
Вы также можете воспользоваться delete
чтобы удалить глобальную переменную если ключевое слово var
не было использовано чтобы объявить переменную:
g = 17; delete g;
Смотри delete
чтобы получить дополнительную информацию.