I am trying to iterate over all the globals defined in a website, but in doing so I am also getting the native browser functions.
var numf=0; var nump=0; v
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.
I tried a different approach. This is only tested for firefox, and 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
almost all of these will fail, because:
function notNative(){}
notNative.toString = String.bind(0, "function notNative() { [native code] }");
console.log( notNative.toString() );
instead:
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());
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:
function Empty(){}
)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.
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
.