Выразительный JavaScript (Хавербеке) - страница 61

>Rabbit.prototype.dance = function() {

>  console.log("А " + this.type + " кролик танцует джигу.");

>};

>killerRabbit.dance();

>// → А убийственный кролик танцует джигу.

Это удобно. Но в некоторых случаях это приводит к проблемам. В предыдущих главах мы использовали объект как способ связать значения с именами – мы создавали свойства для этих имён, и давали им соответствующие значения. Вот пример из 4-й главы:

>var map = {};

>function storePhi(event, phi) {

>  map[event] = phi;

>}


>storePhi("пицца", 0.069);

>storePhi("тронул дерево", -0.081);

Мы можем перебрать все значения фи в объекте через цикл >for/>in, и проверить наличие в нём имени через оператор >in. К сожалению, нам мешается прототип объекта.

>Object.prototype.nonsense = "ку";

>for (var name in map)

>  console.log(name);

>// → пицца

>// → тронул дерево

>// → nonsense

>console.log("nonsense" in map);

>// → true

>console.log("toString" in map);

>// → true


>// Удалить проблемное свойство

>delete Object.prototype.nonsense;

Это же неправильно. Нет события под названием >“nonsense”. И тем более нет события под названием >“toString”.

Занятно, что >toString не вылезло в цикле >for/>in, хотя оператор >in возвращает >true на его счёт. Это потому, что JavaScript различает счётные и несчётные свойства.

Все свойства, которые мы создаём, назначая им значение – счётные. Все стандартные свойства в >Object.prototype – несчётные, поэтому они не вылезают в циклах >for/>in.

Мы можем объявить свои несчётные свойства через функцию >Object.defineProperty, которая позволяет указывать тип создаваемого свойства.

>Object.defineProperty(Object.prototype, "hiddenNonsense", {

>  enumerable: false, value: "ку"

>});

>for (var name in map)

>  console.log(name);

>// → пицца

>// → тронул дерево

>console.log(map.hiddenNonsense);

>// → ку

Теперь свойство есть, а в цикле оно не вылезает. Хорошо. Но нам всё ещё мешает проблема с оператором >in, который утверждает, что свойства >Object.prototype присутствуют в нашем объекте. Для этого нам понадобится метод >hasOwnProperty.

>console.log(map.hasOwnProperty("toString"));

>// → false

Он говорит, является ли свойство свойством объекта, без оглядки на прототипы. Часто это более полезная информация, чем выдаёт оператор >in.

Если вы волнуетесь, что кто-то другой, чей код вы загрузили в свою программу, испортил основной прототип объектов, я рекомендую писать циклы >for/>in так:

>for (var name in map) {

>  if (map.hasOwnProperty(name)) {

>    // ... это наше личное свойство

>  }

>}

Объекты без прототипов

Но кроличья нора на этом не заканчивается. А если кто-то зарегистрировал имя >hasOwnProperty в объекте