检测功能是否为浏览器的原生功能

时间:2011-07-06 15:26:38

标签: javascript global-variables

我正在尝试迭代网站中定义的所有全局变量,但这样做我也获得了本机浏览器功能。

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 个答案:

答案 0 :(得分:14)

您可以在方法上调用继承的.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方法。其次,我们使用正则表达式进行检查,这样我们就不会被函数体内的注释所迷惑。

答案 1 :(得分:10)

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. null或undefined;
  2. param实际上是一个函数;
  3. param是Function.prototype本身(这是一个特例,Function.prototype.toString提供function Empty(){}
  4. 函数体正好是function <valid_function_name> (<valid_param_list>) { [native code] }
  5. 正则表达式有点复杂,但它实际上在我的4GB lenovo笔记本电脑(双核心)上以相当快的速度运行:

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

    3023ms。因此,一旦JIT都运行,该功能需要大约3微秒才能运行。

    适用于所有浏览器。以前,我使用了Function.prototype.toString.call,这会导致IE崩溃,因为在IE中,DOM元素方法和窗口方法都不是函数,而是对象,而且它们没有toString方法。字符串构造函数优雅地解决了这个问题。

答案 2 :(得分:0)

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的“干净”版本。

答案 3 :(得分:-1)

我尝试了不同的方法。这仅针对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

答案 4 :(得分:-2)

几乎所有这些都会失败,因为:

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