Franck Freiburger
Franck Freiburger

Reputation: 28448

How to determine that a JavaScript function is native (without testing '[native code]')

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

Answers (2)

Nina Scholz
Nina Scholz

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

Thomas
Thomas

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

Related Questions