четверг, 21 мая 2015 г.

Как определить, является ли функция нативной

;(function() {

  // Используется для разложения на составляющие внутреннего `[[Class]]` значений
  var toString = Object.prototype.toString;

  // Используется для разложения на составляющие декомпилированного
  // исходного кода функции
  var fnToString = Function.prototype.toString;

  // Используется для определения конструкторов среды (Safari > 4;
  // по сути, предназначено специально для типизированных массивов)
  var reHostCtor = /^\[object .+?Constructor\]$/;

  // Составление регулярного выражения на основе часто употребляемого
  // нативного метода в качестве шаблона.
  // Выбираем `Object#toString`, так как вполне вероятно, что он ещё не задействован.
  var reNative = RegExp('^' +
    // Применяем `Object#toString` к строке
    String(toString)
    // Избавляемся от любых специальных символов регулярных выражений
    .replace(/[.*+?^${}()|[\]\/\\]/g, '\\$&')
    // Заменяем упоминания `toString` на `.*?`, чтобы сохранить обобщённый вид шаблона.
    // Заменяем `for ...` и тому подобное для поддержки окружений вроде Rhino,
    // которые добавляют дополнительную информацию, такую как арность метода.
    .replace(/toString|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$'
  );

  function isNative(value) {
    var type = typeof value;
    return type == 'function'
      // Используем `Function#toString`, чтобы обойти собственный метод
      // `toString` самого значения и избежать ложного результата.
      ? reNative.test(fnToString.call(value))
      // На всякий случай выполняем проверку на наличие объектов среды, так
      // как некоторые окружения могут представлять компоненты вроде
      // типизированных массивов как методы DOM, что может не соответствовать
      // нормальному нативному паттерну.
      : (value && type == 'object' && reHostCtor.test(toString.call(value))) || false;
  }

  // экспортируем в удобном для вас виде
  module.exports = isNative;
}());

Комментариев нет:

Отправить комментарий