Reputation: 28448
I would like to know if there is a way to differentiate a JavaScript script function (function(){}
) from a JavaScript native function (like Math.cos
).
I already know the func.toString().indexOf('[native code]') != -1
trick but I was wondering if there is another way to detect it.
context:
I need to create a No-op forwarding ES6 Proxy that can handle native functions on an object but it fails with TypeError: Illegal invocation
(see Illegal invocation error using ES6 Proxy and node.js).
To workaround this I .bind()
all my functions in the get
handler of my Proxy but if I could detect native function effectively, I will only need to .bind()
these native functions.
more details: https://github.com/FranckFreiburger/module-invalidate/blob/master/index.js#L106
note:
(function() {}).toString() -> "function () {}"
(function() {}).prototype -> {}
(require('os').cpus).toString() -> "function getCPUs() { [native code] }"
(require('os').cpus).prototype -> getCPUs {}
(Math.cos).toString() -> "function cos() { [native code] }"
(Math.cos).prototype -> undefined
(Promise.resolve().then).toString() -> "function then() { [native code] }"
(Promise.resolve().then).prototype -> undefined
edit:
For the moment, the best solution is to test !('prototype' in fun)
but it will not work with require('os').cpus
...
Upvotes: 19
Views: 3141
Reputation: 386654
You could try
to use a Function
constructor with the toString
value of the function. If it does not throw an error, then you get a custom function, otherwise you have a native function.
function isNativeFn(fn) {
try {
void new Function(fn.toString());
} catch (e) {
return true;
}
return false;
}
function customFn() { var foo; }
console.log(isNativeFn(Math.cos)); // true
console.log(isNativeFn(customFn)); // false
console.log(isNativeFn(customFn.bind({}))); // true, because bind
Upvotes: 16
Reputation: 12637
My summary on this topic: don't use it, it doesn't work. You can not certainly detect wether a function is native, because Function#bind()
also creates "native" functions.
function isSupposedlyNative(fn){
return (/\{\s*\[native code\]\s*\}/).test(fn);
}
function foo(){ }
var whatever = {};
console.log("Math.cos():", isSupposedlyNative( Math.cos ));
console.log("foo():", isSupposedlyNative( foo ));
console.log("foo.bind():", isSupposedlyNative( foo.bind(whatever) ));
And since the Version by John-David Dalton, which Tareq linked to in this comment, does basically the same that code doesn't work either. I've checked it.
And the approach from Nina works on a similar principle, because again it is the [native code]
part in the function body wich throws the error when trying to parse it into a new function.
The only secure way to determine wether the function you're dealing with is the native function, is to hold a reference to the native function and compare your function against that reference, but I guess this is no option for your use case.
Upvotes: 8