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

9.5.3. Имя конструктора

9.5.3. Имя конструктора

Основная проблема использования оператора instanceof или свойства constructor для определения класса объекта проявляется при наличии нескольких контекстов выполнения и, соответственно, при наличии нескольких копий функций-конструкторов. Эти функции могут быть совершенно идентичными, но разными объектами, как следствие, не равными друг другу.

Одно из возможных решений проблемы заключается в том, чтобы использовать в качестве идентификатора класса имя функции-конструктора вместо самой функции. Конструктор Array в одном окне не будет равен конструктору Array в другом окне, но их имена будут равны. Некоторые реализации JavaScript обеспечивают доступ к имени функции через нестандартное свойство name объекта функции. Для реализаций, где свойство name отсутствует, можно преобразовать функцию в строку и извлечь имя из нее. (Этот прием использовался в разделе 9.4, где демонстрировалось добавление в класс Function метода getName().)

В примере 9.4 определяется функция type(), возвращающая тип объекта в виде строки. Простые значения и функции она обрабатывает с помощью оператора typeof. Для объектов она возвращает либо значение атрибута class, либо имя конструктора. В своей работе функция type() использует функцию classof() из примера 6.4 и метод Function.getName() из раздела 9.4. Для простоты реализация этой функции и метода включена в пример.

Пример 9.4. Функция type() для определения типа значения

/**
 * Возвращает тип значения в виде строки:
 *  -Если о - null, возвращает "null", если о - NaN, возвращает "пап”.
 *  -Если typeof возвращает значение, отличное от "object", возвращает это значение.
 *   (Обратите внимание, что некоторые реализации идентифицируют объекты
 *   регулярных выражений как функции.)
 *  -Если значение атрибута class объекта о отличается от "Object",
 *   возвращает это значение.
 *  -Если о имеет свойство constructor, а конструктор имеет имя, возвращает
 *   имя конструктора.
 *  -Иначе просто возвращает "Object".
**/
function type(o) {
  var t, c, n; // type, class, name
  // Специальный случай для значения null:
  if (о === null) return "null":
  // Другой специальный случай: NaN - единственное значение, не равное самому себе:
  if (о !== о) return "nan";
  // Применять typeof для любых значений, отличных от "object".
  // Так идентифицируются простые значения и функции,
  if ((t = typeof о) !== "object") return t;
  // Вернуть класс объекта, если это не "Object".
  // Так идентифицируется большинство встроенных объектов,
  if ((с = classof(o)) !== "Object") return с;
  // Вернуть имя конструктора объекта, если имеется
  if (о.constructor && typeof о.constructor === "function" &&
    (n = о.constructor.getName())) return n;
  // He удалось определить конкретный тип, поэтому остается лишь
  // просто вернуть "Object"
  return "Object";
}
// Возвращает класс объекта,
function classof(o) {
  return Object.prototype.toString.call(о).slice(8,-1);
};
// Возвращает имя функции (может быть "") или null - для объектов,
// не являющихся функциями
Function.prototype.getName = function() {
  if ("name" in this) return this.name;
  return this.name = this.toString().match(/functions*([^(]*)(/)[1];
):

Этот прием, основанный на использовании имени конструктора для идентификации класса объекта, имеет ту же проблему, что и прием на основе использования свойства constructor: не все объекты имеют свойство constructor. Кроме того, не все функции имеют имена. Если определить конструктор, используя выражение определения неименованной функции, метод getName() будет возвращать пустую строку:

// Этот конструктор не имеет имени
var Complex = function(x,у) { this.r = х; this.і = у; }
// Этот конструктор имеет имя
var Range = function Range(f.t) { this.from = f; this.to = t; }

Оглавление книги


Генерация: 0.065. Запросов К БД/Cache: 0 / 0
поделиться
Вверх Вниз