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

May 4, 2015

Время от времени мне приходится проверять, является ли та или иная
функция нативной — это важная часть проверки, была ли функция предоставлена
браузером или это порождение постороннего шима, замаскированное под встроенный
компонент. Лучший способ выполнения такой проверки — это, конечно же, оценка
значения toString, возвращённого функцией.

JavaScript


Код, требуемый для этого, довольно прост:

function isNative(fn) {
return (/{s*[native code]s*}/).test('' + fn);
}

Вся суть состоит в том, чтобы конвертировать функцию в строчное представление и
выполнить сопоставление строки с регулярными выражениями.
Лучшего способа подтвердить, что это нативная функция, не существует!

Обновление!


Создатель библиотеки lodash, Джон-Дэвид Далтон (John-David Dalton), предложил
лучшее решение:

;(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;
}());


И вот теперь у нас точно есть лучший подход для определения, является ли метод нативным.
Естественно, не стоит использовать его для обеспечения безопасности — это лишь признак того,
что функция нативна.


Source: http://frontender.info/

Комментарии

comments powered by Disqus