Вместо проверки наличия отдельных свойств иногда бывает необходимо обойти все имеющиеся свойства или получить список всех свойств объекта. Обычно для этого используется цикл
for/in
, однако стандарт ECMAScript 5 предоставляет две удобные альтернативы.
Инструкция цикла
for/in
рассматривалась в разделе 5.5.4. Она выполняет тело цикла для каждого перечислимого свойства (собственного или унаследованного) указанного объекта, присваивая имя свойства переменной цикла. Встроенные
методы, наследуемые объектами, являются неперечислимыми, а свойства, добавляемые в объекты вашей программой, являются перечислимыми (если только не использовались функции, описываемые ниже, позволяющие сделать свойства неперечислимыми). Например:
var о = {х:1, у:2, z:3}; // Три собственных перечислимых свойства
console.log(p); // Выведет х, у и z, но не toString
Некоторые библиотеки добавляют новые методы (или другие свойства) в объект
Object.prototype
, чтобы они могли быть унаследованы и быть доступны всем объектам. Однако до появления стандарта ECMAScript 5 отсутствовала возможность сделать эти дополнительные методы неперечислимыми, поэтому они оказывались доступными для перечисления в циклах
for/in
. Чтобы решить эту проблему, может потребоваться фильтровать свойства, возвращаемые циклом
for/in
. Ниже приводятся два примера реализации такой фильтрации:
fог(р in о) {
if (!о.hasOwnProperty(p)) continue; // Пропустить унаследованные свойства
}
for(p in о) {
if (typeof о[р] === "function”) continue; // Пропустить методы
}
В примере 6.2 определяются вспомогательные функции, использующие цикл for/in для управления свойствами объектов. Функция extend, в частности, часто используется в библиотеках JavaScript. [9]
9
Функция extend, представленная здесь, реализована правильно, но она не компенсирует хорошо известную проблему в Internet Explorer. Более надежная версия функции extend будет представлена в примере 8.3.
Пример 6.2. Вспомогательные функции, используемые для перечисления свойств объектов
/*
* Копирует перечислимые свойства из объекта р в объект о и возвращает о.
* Если о и р имеют свойства с одинаковыми именами, значение свойства
* в объекте о затирается значением свойства из объекта р.
* Эта функция не учитывает наличие методов доступа и не копирует атрибуты.
*/
function extend(o, р) {
fоr(ргор in
р) { // Для всех свойств в р.
о[ргор] = р[prop]; // Добавить свойство в о.
}
return о;
}
/*
* Копирует перечислимые свойства из объекта р в объект о и возвращает о.
* Если о и р имеют свойства с одинаковыми именами, значение свойства
* в объекте о остается неизменным.
* Эта функция не учитывает наличие методов доступа и не копирует атрибуты.
*/
function merge(o, р) {
fоr(ргор in р) { // Для всех свойств в р.
if (о.hasOwnProperty[prop]) continue; // Кроме имеющихся в о.
о[prop] = р[prop]; // Добавить свойство в о.
}
return о;
}
/*
* Удаляет из объекта о свойства, отсутствующие в объекте р.
* Возвращает о.
*/
function restricts, р) {
fоr(prop in о) { // Для всех свойств в о
if (!(prop in р)) delete о[prop]; // Удалить, если отсутствует в р
}
return о;
}
/*
* Удаляет из объекта о свойства, присутствующие в объекте р. Возвращает о.
*/
function subtracts, р) {
for(prop in р) { // Для всех свойств в р
delete о[ргор]; // Удалить из о (удаление несуществующих
// свойств можно выполнять без опаски)
}
return о;
}
/*
* Возвращает новый объект, содержащий свойства, присутствующие хотя бы в одном
* из объектов, о или р. Если оба объекта, о и р, имеют свойства с одним
* и тем же именем, используется значение свойства из объекта р.
*/
function union(o,p) { return extend(extend({},о), p); }