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

asa*_*ams 23 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);
    }
}
Run Code Online (Sandbox Code Playgroud)

有没有办法确定某个函数是浏览器的本机函数还是脚本中创建的函数?

jAn*_*ndy 14

您可以.toString()在方法上调用继承的函数并检查结果.本机方法会有一个块[native code].

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

更新是因为很多评论员都希望得到一些澄清,人们确实需要这样的检测.为了使这个检查确实保存,我们应该使用这一行:

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

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

  • @joekit如果`toString`被覆盖,你应该可以做`Function.prototype.toString.call(obj).indexOf('[native code]');`使用RegExp可能更好.尝试对自己调用函数,它会出现**本地**,因为它出现在字符串中. (3认同)
  • @jAndy这是万无一失的吗?我认为`toString`在所有现代浏览器中都不起作用. (2认同)
  • 请注意,这不是完美的解决方案.结帐https://gist.github.com/jdalton/5e34d890105aca44399f (2认同)

Yon*_*ong 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)));
}
Run Code Online (Sandbox Code Playgroud)

这应该足够好了.此函数执行以下测试:

  1. null或undefined;
  2. param实际上是一个函数;
  3. param是Function.prototype本身(这是一个特例,Function.prototype.toString给出function Empty(){})
  4. 函数体是完全正确的 function <valid_function_name> (<valid_param_list>) { [native code] }

正则表达式有点复杂,但它实际上在我的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;
Run Code Online (Sandbox Code Playgroud)

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

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