(Из книги "Говоря на языке JavaScript").
Эта секция разъясняет две основные концепции объектно-ориентированного программирования в JavaScript: отдельные объекты и конструкторы (последние можно назвать фабриками объектов, подобно тому, как это организованно в использующих классы языках программирования).
Как у всех значений, у объекта есть свойства. Вы можете просто рассматривать объект как набор свойств, каждое из которых представляет собой пару ключ/значение. Ключ это строка, а значение может быть любого типа из доступных в JavaScript.
Вы можете создавать объекты непосредственно с помощью соответствующего литерала:
Ключ для свойства представляет собой строку. Мы вызываем значение по ключу с помощью оператора-точки. Но это возможно лишь в случаях, когда ключ соответствует требованиям, предъявляемым к идентификаторам (см. Идентификаторы и имена переменных). Если вы хотите в качестве ключей использовать произвольные строки, вам следует заключать их в кавычки при описании объекта и использовать квадратные скобки при чтении и записи его свойств:
Если вы извлекаете метод, он теряет свою связь с объектом. Это уже не метод, а просто функция, и слово
Каждая функция располагает своим собственным указателем
До сих пор вам могло казаться, что объекты JavaScript это лишь соответствия строк и значений, просто некие словари. Тем не менее, объекты в JavaScript поддерживают еще и возможность, делающую их подлинными объектно-ориентированными инструментами: наследование. Здесь мы не будем подробно останавливаться на том, как оно работает в JavaScript, но дадим простой паттерн, который может стать отправной точкой. Подробности можно узнать из Главы 17.
Помимо своей классической роли, функции и методы могут быть в JavaScript еще и конструкторами, фабриками объектов. В таких случаях их вызывают с оператором
Чтобы использовать
Отдельный объект
Вы можете создавать объекты непосредственно с помощью соответствующего литерала:
'use strict';varjane={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';varjane={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 для перебора элементов массива:
varjane={name:'Jane',friends:['Tarzan','Cheeta'],logHiToFriends:function(){'use strict';this.friends.forEach(function(friend){// `this` is undefined hereconsole.log(this.name+' says hi to '+friend);});}}
Вызов функции logHiToFriends порождает ошибку:jane.logHiToFriends() // Выведет TypeError: Cannot read property 'name' of undefined.
Давайте рассмотрим два способа устранить эту неприятность. Во-первых, мы можем сохранить
this в другой переменной:
logHiToFriends:function(){'use strict';varthat=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 datafunctionPoint(x,y){this.x=x;this.y=y;}// MethodsPoint.prototype.dist=function(){returnMath.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
Комментариев нет:
Отправить комментарий