JavaScript. Подробное руководство, 6-е издание, стр. 114
<b> var t, c, n; // type, class, name</b><b> // Специальный случай для значения null: </b><b> if (о === null) return "null":</b><b> // Другой специальный случай: NaN - единственное значение, не равное самому себе: </b><b> if (о !== о) return "nan";</b><b> // Применять typeof для любых значений, отличных от "object". </b><b> // Так идентифицируются простые значения и функции, </b><b> if ((t = typeof о) !== "object") return t;</b><b> // Вернуть класс объекта, если это не "Object".</b><b> // Так идентифицируется большинство встроенных объектов, </b><b> if ((с = classof(o)) !== "Object") return с;</b><b> // Вернуть имя конструктора объекта, если имеется</b><b> if (о.constructor && typeof о.constructor === "function" &&</b><b> (n = о.constructor.getName())) return n;</b><b> // He удалось определить конкретный тип, поэтому остается лишь </b><b> // просто вернуть "Object" </b><b> return "Object";</b><b>}</b><b>// Возвращает класс объекта, </b><b>function classof(o) {</b><b> return Object.prototype.toString.call(о).slice(8,-1);</b><b>};</b><b>// Возвращает имя функции (может быть "") или null - для объектов,</b><b>// не являющихся функциями </b><b>Function.prototype.getName = function() {</b><b> if ("name" in this) return this.name;</b><b> return this.name = this.toString().match(/function\s*([^(]*)\(/)[1];</b><b>):</b>Этот прием, основанный на использовании имени конструктора для идентификации класса объекта, имеет ту же проблему, что и прием на основе использования свойства
<b>constructor</b><b>constructor</b><b>getName()</b><b>// Этот конструктор не имеет имени</b><b>var Complex = function(x,у) { this.r = х; this.і = у; }</b><b>// Этот конструктор имеет имя</b><b>var Range = function Range(f.t) { this.from = f; this.to = t; }</b>9.5.4. Грубое определение типа
Ни один из приемов определения класса объекта, описанных выше, не свободен от проблем, по крайней мере, в клиентском JavaScript. Альтернативный подход состоит в том, чтобы вместо вопроса «какому классу принадлежит объект?» задать вопрос «что может делать этот объект?». Этот подход является типичным в таких языках программирования, как Python и Ruby, и носит название грубое определение типа (<duck-typing, или «утиная типизация») в честь высказывания (часто приписываемого поэту Джеймсу Уиткомбу Райли (James Whitcomb Riley)):
Когда я вижу птицу, которая ходит, как утка, плавает, как утка и крякает, как утка, я называю ее уткой.
Для программистов на языке JavaScript этот афоризм можно интерпретировать так: «Если объект может ходить, плавать и крякать как объект класса Duck, его можно считать объектом класса Duck, даже если он не наследует объект-прототип класса Duck».
Примером может служить класс
<b>Range</b><b>Range()</b><b>includes()</b><b><=</b><b>includes()</b><b>var lowercase = new Range("a", 'z');</b><b>var thisYear = new Range(new Date(2009, 0, 1), new Date(2010, 0, 1));</b>Метод
<b>foreach()</b><b>Range</b><b>Math.ceil()</b>++В качестве еще одного примера вспомним объекты, подобных массивам, обсуждавшиеся в разделе 7.11. Во многих случаях нам не требуется знать, действительно ли объект является экземпляром класса
<b>Array</b><b>length</b><b>length</b>Однако имейте в виду, что свойство
<b>length</b><b>length</b><b>length</b>