检测功能是否为浏览器本地功能
我正在尝试遍历网站中定义的所有全局变量,但是这样做时我也获得了本地浏览器功能。检测功能是否为浏览器本地功能
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
}
现在我们正在使用从Function
的prototype
这使得它不太可能,如果不是不可能一些其他的脚本已覆盖了该.toString
方法toString
方法。其次,我们使用正则表达式进行检查,所以我们不能被函数体内的注释所迷惑。
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)));
}
这应该是够好的了。该功能进行以下测试:
- null或undefined;
- 该参数实际上是一个函数;
- 的参数是Function.prototype的本身(这是一种特殊情况,其中Function.prototype.toString给
function Empty(){}
) - 函数体是完全
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
几乎所有的这些都将失败,因为:
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());
你能阐述为什么你的解决方案更好,以及这是如何工作的? – rene
如果的toString没有被覆盖这只会工作,不是吗? – joekarl
@jAndy这是否简单?我认为'toString'在所有现代浏览器中都不起作用。 – William
@joekit如果'toString'被覆盖,你应该可以做'Function.prototype.toString.call(obj).indexOf('[native code]');'这也可能是使用RegExp更好的主意。尝试对自身调用函数,并且它会以** native **的形式出现,因为它出现在字符串中。 – William