Определить, если функция является родной для браузера - PullRequest
22 голосов
/ 06 июля 2011

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

var numf=0; var nump=0; var numo=0; 
for(var p in this) { 
    if(typeof(this[p]) === "function"){
        numf+=1;
        console.log(p+"()");
    } else if(typeof p != 'undefined'){
        nump+=1;
        console.log(p);
    } else { 
        numo+=1;
        console.log(p);
    }
}

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

Ответы [ 5 ]

14 голосов
/ 06 июля 2011

Вы можете вызвать унаследованную функцию .toString() в методах и проверить результат. Нативные методы будут иметь блок типа [native code].

if( this[p].toString().indexOf('[native code]') > -1 ) {
    // yep, native in the browser
}

Обновление, потому что многие комментаторы хотят получить разъяснения, и у людей действительно есть требование для такого обнаружения. Чтобы эта проверка действительно сохранилась, нам, вероятно, следует использовать строку строки:

if( /\{\s+\[native code\]/.test( Function.prototype.toString.call( this[ p ] ) ) ) {
    // yep, native
}

Теперь мы используем метод .toString из prototype из Function, что делает его очень маловероятным, если не невозможным, каким-то другим сценарием, перезаписавшим метод toString. Во-вторых, мы проверяем регулярное выражение, поэтому мы не можем быть одураченными комментариями внутри тела функции.

10 голосов
/ 24 сентября 2011
function isFuncNative(f) {
       return !!f && (typeof f).toLowerCase() == 'function' 
       && (f === Function.prototype 
       || /^\s*function\s*(\b[a-z$_][a-z0-9$_]*\b)*\s*\((|([a-z$_][a-z0-9$_]*)(\s*,[a-z$_][a-z0-9$_]*)*)\)\s*{\s*\[native code\]\s*}\s*$/i.test(String(f)));
}

это должно быть достаточно хорошо. эта функция выполняет следующие тесты:

  1. пусто или не определено;
  2. параметр на самом деле является функцией;
  3. параметр - это сам Function.prototype (это особый случай, когда Function.prototype.toString дает function Empty(){})
  4. тело функции точно function <valid_function_name> (<valid_param_list>) { [native code] }

регулярное выражение немного сложное, но на моем 4-Гбайтном ноутбуке lenovo (duo core) он работает довольно прилично быстро в chrome:

var n = (new Date).getTime(); 
for (var i = 0; i < 1000000; i++) {
    i%2 ? isFuncNative(isFuncNative) : 
          isFuncNative(document.getElementById);
}; 
(new Date).getTime() - n;

3023ms. таким образом, функция запускается где-то около 3 микросекунд после того, как все будет JIT.

Работает во всех браузерах. Ранее я использовал Function.prototype.toString.call, это приводит к аварийному завершению работы IE, поскольку в IE методы элемента DOM и методы окна - это НЕ функции, а объекты, и у них нет метода toString. Строковый конструктор решает проблему элегантно.

0 голосов
/ 27 июля 2018

Function.prototype.toString может быть подделан, что-то вроде этого:

Function.prototype.toString = (function(_toString){
  return function() {
    if (shouldSpoof) return 'function() { [native code] }'
    return _toString.apply(this, arguments)
  }
})(Function.prototype.toString)

Вы можете определить, является ли Function.prototype.toString вандализмом, поймав в ловушку .apply(), .call(), .bind() (и другие).

И если это так, вы можете получить «чистую» версию Function.prototype.toString из недавно введенной IFRAME.

0 голосов
/ 30 июня 2017

почти все из них потерпит неудачу, потому что:

function notNative(){
this.toString = "[native code]";
}

вместо

Function.prototype.isNative = function(){
return Function.prototype.toString.call(this).slice(-14, -3) === "native code";
};

console.log(alert.isNative());
console.log(String.isNative());
function foo(){}
console.log(foo.isNative());
0 голосов
/ 24 января 2015

Я попробовал другой подход. Это проверено только для Firefox и Chrome.

function isNative(obj){
    //Is there a function?
    //You may throw an exception instead if you want only functions to get in here.

    if(typeof obj === 'function'){
        //Check does this prototype appear as an object?
        //Most natives will not have a prototype of [object Object]
        //If not an [object Object] just skip to true.
        if(Object.prototype.toString.call(obj.prototype) === '[object Object]'){
            //Prototype was an object, but is the function Object?
            //If it's not Object it is not native.
            //This only fails if the Object function is assigned to prototype.constructor, or
            //Object function is assigned to the prototype, but
            //why you wanna do that?
            if(String(obj.prototype.constructor) !== String(Object.prototype.constructor)){
                return false;
            }
        }
    }
    return true;
}

function bla(){}

isNative(bla); //false
isNative(Number); //true
isNative(Object); //true
isNative(Function); //true
isNative(RegExp); //true
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...