Detect if function is native to browser
Function.prototype.toString
can be spoofed, something kinda like this:
Function.prototype.toString = (function(_toString){
return function() {
if (shouldSpoof) return 'function() { [native code] }'
return _toString.apply(this, arguments)
}
})(Function.prototype.toString)
You can detect if Function.prototype.toString
is vandalized by trapping .apply()
, .call()
, .bind()
(and others).
And if it was, you can grab a "clean" version of Function.prototype.toString
from a newly injected IFRAME
.
You can call the inherited .toString()
function on the methods and check the outcome. Native methods will have a block like [native code]
.
if( this[p].toString().indexOf('[native code]') > -1 ) {
// yep, native in the browser
}
Update because a lot of commentators want some clarification and people really have a requirement for such a detection. To make this check really save, we should probably use a line line this:
if( /\{\s+\[native code\]/.test( Function.prototype.toString.call( this[ p ] ) ) ) {
// yep, native
}
Now we're using the .toString
method from the prototype
of Function
which makes it very unlikely if not impossible some other script has overwritten the toString
method. Secondly we're checking with a regular expression so we can't get fooled by comments within the function body.
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)));
}
this should be good enough. this function does the following tests:
- null or undefined;
- the param is actually a function;
- the param is Function.prototype itself (this is a special case, where Function.prototype.toString gives
function Empty(){}
) - the function body is exactly
function <valid_function_name> (<valid_param_list>) { [native code] }
the regex is a little bit complicated, but it actually runs pretty decently fast in chrome on my 4GB lenovo laptop (duo core):
var n = (new Date).getTime();
for (var i = 0; i < 1000000; i++) {
i%2 ? isFuncNative(isFuncNative) :
isFuncNative(document.getElementById);
};
(new Date).getTime() - n;
3023ms. so the function takes somewhere around 3 micro-sec to run once all is JIT'ed.
It works in all browsers. Previously, I used Function.prototype.toString.call, this crashes IE, since in IE, the DOM element methods and window methods are NOT functions, but objects, and they don't have toString method. String constructor solves the problem elegantly.