JavaScript. Подробное руководство, 6-е издание, стр. 112

<b>  Function.prototype.bind = function(o /*, аргументы */) {</b>

<b>    // Реализация метода bind...</b>

<b>  };</b>

<b>}</b>

Ниже приводятся несколько примеров расширения классов:

<b>// Вызывает функцию f в цикле, количество итераций равно самому числу;</b>

<b>// при этом функции каждый раз передается номер итерации </b>

<b>// Например, чтобы вывести &quot;привет&quot; 3 раза:</b>

<b>// var n = 3;</b>

<b>// n.times(function(n) { console.log(n + &quot; привет&quot;); });</b>

<b>Number.prototype.times = function(f, context) {</b>

<b>  var n = Number(this);</b>

<b>  for(var і = 0; і &lt; n; i++) f.call(context, i);</b>

<b>};</b>

<b>// Определяет метод ES5 String.trim(), если он отсутствует.</b>

<b>// Этот метод удаляет пробельные символы в начале и в конце строки и возвращает ее. </b>

<b>String.prototype.trim = String.prototype.trim || function() {</b>

<b>  if (!this) return this; // He изменять пустую строку</b>

<b>    return this.replace(/^\s+|\s+$/g, &quot;&quot;); // Регулярное выражение</b>

<b>};</b>

<b>// Возвращает имя функции. Если функция имеет свойство name (нестандартное),</b>

<b>// возвращает его значение. Иначе преобразует функцию в строку и извлекает имя из нее.</b>

<b>// Для неименованных функций возвращает пустую строку.</b>

<b>Function.prototype.getName = function() {</b>

<b>  return this.name || this.toString().match(/function\s*([^(]*)\(/)[1];</b>

<b>};</b>

Методы можно также добавлять в

<b>Object, prototype</b>
, тем самым делая их доступными для всех объектов. Однако делать это не рекомендуется, потому что в реализациях, появившихся до ECMAScript 5, отсутствует возможность сделать эти дополнительные методы неперечислимыми. При добавлении новых свойств в
<b>Object.prototype</b>
они становятся доступны для перечисления в любом цикле
<b>for/in</b>
. В разделе 9.8.1 приводится пример использования метода
<b>Object.defineProperty()</b>
, определяемого стандартом ECMAScript 5, для безопасного расширения
<b>Object, prototype</b>
.

Возможность подобного расширения классов, определяемых средой выполнения (такой как веб-броузер), зависит от реализации самой среды. Во многих веб-броузерах, например, допускается добавлять методы в

<b>HTMLElement.prototype</b>
, и такие методы будут наследоваться объектами, представляющими теги HTML в текущем документе. Однако данная возможность не поддерживается в текущей версии Microsoft Internet Explorer, что сильно ограничивает практическую ценность этого приема в клиентских сценариях.

9.5. Классы и типы

В главе 3 уже говорилось, что в языке JavaScript определяется небольшое количество типов:

<b>null, undefined</b>
, логические значения, числа, строки, функции и объекты. Оператор
<b>typeof</b>
(раздел 4.13.2) позволяет отличать эти типы. Однако часто бывает желательно интерпретировать каждый класс как отдельный тип данных и иметь возможность отличать объекты разных классов. Отличать встроенные объекты базового языка JavaScript (и объекты среды выполнения в большинстве реализаций клиентского JavaScript) можно по их атрибуту
<b>class</b>
(раздел 6.8.2), используя прием, реализованный в функции
<b>classof()</b>
из примера 6.4. Но когда класс определяется с помощью приемов, продемонстрированных в этой главе, экземпляры объектов всегда содержат в атрибуте
<b>class</b>
значение «Object», поэтому функция
<b>classof()</b>
в данной ситуации оказывается бесполезной.

В следующих подразделах описываются три приема определения класса произвольного объекта: оператор

<b>instanceof</b>
, свойство
<b>constructor</b>
и имя функции-конструктора. Однако ни один из этих приемов не дает полной гарантии, поэтому в разделе 9.5.4 мы обсудим прием грубого определения типа (duck-typing) - философии программирования, в которой центральное место отводится возможностям объекта (т. е. наличию тех или иных методов), а не его принадлежности к какому-либо классу.

9.5.1. Оператор instanceof

Оператор

<b>instanceof</b>
был описан в разделе 4.9.4. Слева от оператора должен находиться объект, для которого выполняется проверка принадлежности к классу, а справа - имя функции-конструктора, представляющей класс. Выражение
<b>о instanceof с</b>
возвращает
<b>true</b>
, если объект о наследует
<b>с.prototype</b>
. При этом наследование необязательно может быть непосредственным. Если
<b>о</b>
наследует объект, который наследует объект, наследующий
<b>с.prototype</b>
, выражение все равно вернет
<b>true</b>
.

Как отмечалось выше в этой главе, конструкторы выступают в качестве наружной вывески классов, а фундаментальная идентификация классов проводится прототипами. Несмотря на то что в операторе

<b>instanceof</b>
используется функция» конструктор, этот оператор в действительности проверяет прототип, наследуемый объектом, а не конструктор, с помощью которого он был создан.

Если необходимо проверить, входит ли некоторый определенный прототип в цепочку прототипов объекта без использования функции-конструктора, как промежуточного звена, можно воспользоваться методом

<b>isPrototypeOf()</b>
. Например, ниже показано, как проверить принадлежность объекта г к классу range, определенному в примере 9.1: