【问题标题】:How to determine that a JavaScript function is native (without testing '[native code]')如何确定 JavaScript 函数是原生的(无需测试“[原生代码]”)
【发布时间】:2017-03-04 10:03:29
【问题描述】:

我想知道是否有办法区分 JavaScript 脚本函数 (function(){}) 和 JavaScript 本机函数(如 Math.cos)。
我已经知道func.toString().indexOf('[native code]') != -1 技巧,但我想知道是否有其他方法可以检测到它。

上下文:
我需要创建一个 No-op 转发 ES6 代理,它可以处理对象上的本机函数,但它以 TypeError: Illegal invocation 失败(请参阅 Illegal invocation error using ES6 Proxy and node.js)。

要解决这个问题,我 .bind() 我的代理的 get 处理程序中的所有函数,但如果我能有效地检测到本机函数,我只需要 .bind() 这些本机函数。

更多详情:https://github.com/FranckFreiburger/module-invalidate/blob/master/index.js#L106

注意:

(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

编辑:
目前,最好的解决方案是测试!('prototype' in fun),但它不适用于require('os').cpus ...

【问题讨论】:

  • 你检查过这个davidwalsh.name/detect-native-function 吗?
  • 你为什么要另一种方式?
  • @Tareq,detect-native-function 使用类似于func.toString().indexOf('[native code]') != -1的fnToString和regexp
  • @jonrsharpe,我需要创建一个 No-op 转发 ES6 代理,它可以处理对象上的本机函数,但这会失败(请参阅stackoverflow.com/questions/42496414/…)。
  • 在问题中包含该上下文会有所帮助,因此人们不会建议具有类似限制的其他方法。

标签: javascript node.js function native


【解决方案1】:

您可以try 使用带有toString 函数值的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 

【讨论】:

  • 这是try ... catch 块的本质,但没有indexOf 或正则表达式,我看不出有什么不同。
  • 签出console.log(isNativeFn( customFn.bind( {/*whatever*/} ));
  • bind() 方法创建了一个新函数”,显然是原生的。
  • 正确,但通过 ES6 代理访问时不会抛出 TypeError: Illegal invocation
  • 你的 isNativeFn 可以被绕过。我伪造一个函数:var a=(function(){}).bind(null); isNativeFn(a); //true
【解决方案2】:

我对这个话题的总结:不要使用它,它不起作用。你不能确定一个函数是否是原生的,因为Function#bind() 也创建了“原生”函数。

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) ));

并且由于 Tareq 在此评论中链接到的 John-David Dalton 的版本基本上与此代码相同,因此代码也不起作用。我已经检查过了。

Nina 的方法也有类似的原理,因为函数体中的 [native code] 部分在尝试将其解析为新函数时会引发错误。

确定您正在处理的函数是否是本机函数的唯一安全方法是保存对本机函数的引用并将您的函数与该引用进行比较,但我想这不是您的用例的选择.

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-07-13
    • 2013-10-05
    • 1970-01-01
    • 1970-01-01
    • 2020-07-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多