(Из книги "Говоря на языке JavaScript").
Эта секция разъясняет две основные концепции объектно-ориентированного программирования в JavaScript: отдельные объекты и конструкторы (последние можно назвать фабриками объектов, подобно тому, как это организованно в использующих классы языках программирования).
Как у всех значений, у объекта есть свойства. Вы можете просто рассматривать объект как набор свойств, каждое из которых представляет собой пару ключ/значение. Ключ это строка, а значение может быть любого типа из доступных в JavaScript.
Вы можете создавать объекты непосредственно с помощью соответствующего литерала:
Ключ для свойства представляет собой строку. Мы вызываем значение по ключу с помощью оператора-точки. Но это возможно лишь в случаях, когда ключ соответствует требованиям, предъявляемым к идентификаторам (см. Идентификаторы и имена переменных). Если вы хотите в качестве ключей использовать произвольные строки, вам следует заключать их в кавычки при описании объекта и использовать квадратные скобки при чтении и записи его свойств:
Если вы извлекаете метод, он теряет свою связь с объектом. Это уже не метод, а просто функция, и слово
Каждая функция располагает своим собственным указателем
До сих пор вам могло казаться, что объекты JavaScript это лишь соответствия строк и значений, просто некие словари. Тем не менее, объекты в JavaScript поддерживают еще и возможность, делающую их подлинными объектно-ориентированными инструментами: наследование. Здесь мы не будем подробно останавливаться на том, как оно работает в JavaScript, но дадим простой паттерн, который может стать отправной точкой. Подробности можно узнать из Главы 17.
Помимо своей классической роли, функции и методы могут быть в JavaScript еще и конструкторами, фабриками объектов. В таких случаях их вызывают с оператором
Чтобы использовать
Отдельный объект
Вы можете создавать объекты непосредственно с помощью соответствующего литерала:
'use strict'
;
var
jane
=
{
name
:
'Jane'
,
describe
:
function
()
{
return
'Person named '
+
this
.
name
;
}
};
Только что описанный объект имеет свойства name
и describe
. Можно считывать (“get”) и записывать (“set”) свойства:jane.name // Содержит 'Jane' (get). jane.name = 'John'; // set jane.newProperty = 'abc'; // Новое свойство создается автоматически.
Свойства, содержащие в качестве своих значений функции. как, например
describe
в данном примере, называются методами. Они используют ключевое слово this
чтобы указывать на объект, внутри которого находятся:jane.describe() // Вызов метода, выведет 'Person named John'. jane.name = 'Jane'; jane.describe() // 'Person named Jane'.
Оператор
in
позволяет убедиться, что то или иное свойство существует внутри объекта:'newProperty' in jane // Вернет true. 'foo' in jane // Вернет false.
Если вы пытаетесь обратиться к свойству, которое не существует, вы получите значение
undefined
. Таким образом, предыдущие две проверки могут быть выполнены так:jane.newProperty !== undefined // Вернет true. jane.foo !== undefined // Вернет false.
Оператор
delete
удаляет свойство:delete jane.newProperty // true 'newProperty' in jane // false
Произвольные ключи для свойств
var obj = { 'not an identifier': 123 }; obj['not an identifier'] // 123 obj['not an identifier'] = 456;
Квадратные скобки позволяют вам также вычислять ключи "налету":
var obj = { hello: 'world' }; var x = 'hello'; obj[x] // 'world' obj['hel'+'lo'] // 'world'
Извлечение методов
this
внутри нее приобретает значение undefined
(в строгом режиме). В качестве примера давайте вернемся к прежнему объекту jane
:
'use strict'
;
var
jane
=
{
name
:
'Jane'
,
describe
:
function
()
{
return
'Person named '
+
this
.
name
;
}
};
Допустим, мы хотим извлечь метод describe
из jane
, поместить его в переменную func
и вызвать. К сожалению, так не получится:var func = jane.describe; func() // Выведет TypeError: Cannot read property 'name' of undefined.
Решение заключается в использовании метода
bind(),
который есть у каждой функции (функция, как сказано ранее, это разновидность объекта и сама может обладать методами). bind()
создает новую функцию, внутри которой this
всегда имеет заданное при связывании значение:var func2 = jane.describe.bind(jane); func2() // Выведет 'Person named Jane'.
Функции внутри методов
this
. Это неудобно, если вы помещаете функцию внутрь метода, потому что из такой функции вам становится недоступен this
самого метода. Вот пример, с вызовом forEach
для перебора элементов массива:
var
jane
=
{
name
:
'Jane'
,
friends
:
[
'Tarzan'
,
'Cheeta'
],
logHiToFriends
:
function
()
{
'use strict'
;
this
.
friends
.
forEach
(
function
(
friend
)
{
// `this` is undefined here
console
.
log
(
this
.
name
+
' says hi to '
+
friend
);
});
}
}
Вызов функции logHiToFriends
порождает ошибку:jane.logHiToFriends() // Выведет TypeError: Cannot read property 'name' of undefined.
Давайте рассмотрим два способа устранить эту неприятность. Во-первых, мы можем сохранить
this
в другой переменной:
logHiToFriends
:
function
()
{
'use strict'
;
var
that
=
this
;
this
.
friends
.
forEach
(
function
(
friend
)
{
console
.
log
(
that
.
name
+
' says hi to '
+
friend
);
});
}
Второй путь - воспользоваться тем, что у forEach
есть второй параметр, который позволяет вам предоставлять ссылку на this
:
logHiToFriends
:
function
()
{
'use strict'
;
this
.
friends
.
forEach
(
function
(
friend
)
{
console
.
log
(
this
.
name
+
' says hi to '
+
friend
);
},
this
);
}
Выражения-функции часто используются в качестве аргументов при вызове других функций в JavaScript. Всегда будьте осторожны при использовании this
внутри таких функций.Конструкторы как фабрики объектов
Помимо своей классической роли, функции и методы могут быть в JavaScript еще и конструкторами, фабриками объектов. В таких случаях их вызывают с оператором
new
. Конструкторы, грубо говоря, являются аналогами классов других языков программирования. Традиционно имена функций-конструкторов начинаются с заглавной буквы. Например:
// Set up instance data
function
Point
(
x
,
y
)
{
this
.
x
=
x
;
this
.
y
=
y
;
}
// Methods
Point
.
prototype
.
dist
=
function
()
{
return
Math
.
sqrt
(
this
.
x
*
this
.
x
+
this
.
y
*
this
.
y
);
};
Мы видим, что конструктор состоит из двух частей. Первая, функция Point,
устанавливает свойства порождаемого объекта-экземпляра. Вторая (Point.prototype)
описывает метод объекта. Первая часть (данные) специфична для каждого создаваемого объекта, вторая - одинакова для всех.Чтобы использовать
Point
, мы запускаем его с оператором new
:var p = new Point(3, 5); p.x // 3 p.dist() // 5.830951894845301
p
является экземпляром Point
:p instanceof Point // true
Комментариев нет:
Отправить комментарий