检测功能是否为浏览器本地功能

问题描述:

我正在尝试遍历网站中定义的所有全局变量,但是这样做时我也获得了本地浏览器功能。检测功能是否为浏览器本地功能

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

有没有一种方法可以确定函数是浏览器本机还是脚本中创建的?

您可以调用方法的继承函数.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 
} 

现在我们正在使用从Functionprototype这使得它不太可能,如果不是不可能一些其他的脚本已覆盖了该.toString方法toString方法。其次,我们使用正则表达式进行检查,所以我们不能被函数体内的注释所迷惑。

+0

如果的toString没有被覆盖这只会工作,不是吗? – joekarl

+2

@jAndy这是否简单?我认为'toString'在所有现代浏览器中都不起作用。 – William

+3

@joekit如果'toString'被覆盖,你应该可以做'Function.prototype.toString.call(obj).indexOf('[native code]');'这也可能是使用RegExp更好的主意。尝试对自身调用函数,并且它会以** native **的形式出现,因为它出现在字符串中。 – William

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. 该参数实际上是一个函数;
  3. 的参数是Function.prototype的本身(这是一种特殊情况,其中Function.prototype.toString给function Empty(){}
  4. 函数体是完全function <valid_function_name> (<valid_param_list>) { [native code] }

的正则表达式是有点复杂,但它实际上在我的4GB联想笔记本电脑(双核)上运行速度非常快,铬合金:

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方法。字符串构造函数优雅地解决了这个问题。

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

即使我的浏览器本身支持Promise,也会为'Promise'返回false。 – mpen

+0

是的,我不知道这是为什么。 Promise.prototype.constructor不等于Object.prototype.constructor。我通常不会测试它是否是本地的,并且寻找'then'方法,这就是本地承诺如何解决图书馆承诺的任何方式。如果一切都失败了,我使用'Promise.resolve(nonNative)'来规范所有的承诺。 –

+0

主要适用于Chrome。 'RegExp'返回false。 – trusktr

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

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

你能阐述为什么你的解决方案更好,以及这是如何工作的? – rene