Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/422.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
JavaScript ES6:测试箭头函数、内置函数、常规函数?_Javascript_Function_Ecmascript 6_Ecmascript Harmony_Arrow Functions - Fatal编程技术网

JavaScript ES6:测试箭头函数、内置函数、常规函数?

JavaScript ES6:测试箭头函数、内置函数、常规函数?,javascript,function,ecmascript-6,ecmascript-harmony,arrow-functions,Javascript,Function,Ecmascript 6,Ecmascript Harmony,Arrow Functions,有没有一种优雅的方法将Harmony的细长箭头功能与常规功能和内置功能区分开来 缔约国指出: 箭头函数类似于内置函数,因为缺少.prototype和任何[[Construct]]内部方法。所以new(()=>{})抛出一个TypeError,但在其他方面箭头类似于函数 也就是说,您可以测试箭头功能,如: !(()=>{}).hasOwnProperty("prototype") // true !(function(){}).hasOwnProperty("prototype") // f

有没有一种优雅的方法将Harmony的细长箭头功能与常规功能和内置功能区分开来

缔约国指出:

箭头函数类似于内置函数,因为缺少.prototype和任何[[Construct]]内部方法。所以new(()=>{})抛出一个TypeError,但在其他方面箭头类似于函数

也就是说,您可以测试箭头功能,如:

!(()=>{}).hasOwnProperty("prototype") // true
!(function(){}).hasOwnProperty("prototype") // false
但是对于任何内置函数,测试也会返回
true
,例如
setTimeout
Math.min

如果您获取源代码并检查它是否为
“本机代码”
,那么它在Firefox中可以正常工作,但它似乎不太可靠,也不可移植(其他浏览器实现,NodeJS/iojs):

小型GitHub项目依赖于RegExp检查函数源代码,这并不是很整洁

edit:我尝试了一下JavaScript解析器,它似乎工作得很好——尽管它有点过头了

acorn = require("./acorn");

function fn_sample(a,b){
    c = (d,e) => d-e;
    f = c(--a, b) * (b, a);
    return f;
}

function test(fn){
    fn = fn || fn_sample;
    try {
        acorn.parse("(" + fn.toString() + ")", {
            ecmaVersion: 6,
            onToken: function(token){
                if(typeof token.type == "object" && token.type.type == "=>"){
                    console.log("ArrowFunction found", token);
                }
            }
        });
    } catch(e) {
        console.log("Error, possibly caused by [native code]");
        console.log(e.message);
    }
}

exports.test = test;

ECMAScript放弃了对宿主对象的许多保证,因此扩展了宿主函数。 这使得通过反射访问的属性主要依赖于实现,对一致性几乎没有保证,至少就ecmascript规范而言,W3C规范可能更具体地针对浏览器主机对象

例如,见

表9总结了本规范使用的仅适用于某些ECMAScript对象的内部属性。[...] 主机对象可以通过任何依赖于实现的行为支持这些内部属性,只要它符合本文档中规定的特定主机对象限制

所以内置函数可能是可调用的,但没有原型(即不从函数继承)。或者他们可以有一个

说明书上说他们的行为可能不同。但它们也可以实现所有标准行为,使它们与正常功能无法区分

请注意,我引用的是ES5规范。ES6仍在进行修订,本机对象和宿主对象现在称为外来对象。但是说明书上说的差不多。它规定,即使他们必须履行,但除此之外,只说他们可能履行或不履行所有可选行为。

信不信由你

测试函数的字符串表示中是否存在“=>”可能是最可靠的方法(但不是100%)

显然,我们无法针对您提到的两种情况中的任何一种进行测试—缺少原型属性和缺少
[[Construct]]
,因为这可能会导致主机对象或缺少
[[Construct]]
的内置对象出现误报(
Math.floor
JSON.parse
,等等)

然而,我们可以使用好的
Function.prototype.toString
检查函数表示是否包含“=>”

现在,我一直建议不要使用
Function.prototype.toString
(所谓的函数反编译),因为它依赖于实现,而且历史上不可靠(更多详细信息请参见)

但ES6实际上正在(至少)呈现内置和“用户创建”(因为缺少更好的术语)功能

  • 如果类型(func)是对象并且是内置函数对象或 有一个[[ECMAScriptCode]]内部插槽,然后

    a。返回func的依赖于实现的字符串源代码表示形式。表示法必须符合以下规则

  • toString表示要求:

    • 字符串表示必须具有FunctionDeclaration FunctionExpression、GeneratorDeclaration、, GeneratorExpression、类声明、类表达式、箭头函数, MethodDefinition,或GeneratorMethod,具体取决于实际 对象的特征

    • 在表示字符串中使用和放置空格、行终止符和分号是不正确的 依赖于实现

    • 如果对象是使用ECMAScript代码定义的,并且返回的字符串表示形式不是MethodDefinition或 GeneratorMethod则表示形式必须为 字符串的求值,在以下词法上下文中使用eval 相当于用于创建原始对象的词汇上下文, 它将产生一个新的功能等效对象。那么 返回的源代码不能随意提及 没有被原始函数的源代码自由提及,甚至 如果这些“额外”名称最初在范围内

    • 如果实现无法生成满足这些条件的源代码字符串,那么它必须返回eval将抛出的字符串 SyntaxError异常

    我强调了相关的块

    箭头函数具有内部
    [[ECMAScriptCode]]
    (您可以从14.2.17-箭头函数的评估-到函数创建到函数初始化进行跟踪)

    这意味着它们必须符合:

    ..这意味着它们必须在
    Function.prototype.toString
    的输出中具有=>

    显然,您需要确保“=>”遵循箭头参数,而不仅仅是FunctionBody中的内容:

    function f() { return "=>" }
    
    至于可靠性-请记住,目前任何/所有引擎都支持/可能不支持此行为,并且无论出于何种原因,主机对象的表示可能存在(尽管规范做出了努力)。

    • 将函数转换为字符串
      toString
    • 删除此字符串的所有空格
    • 如果存在索引大于或等于1的
      ”=>“
      ”=>99.99%是一个箭头函数

          F.toString().replace(/\s+/g, '').indexOf(')=>')>=1
      
    演示:
    var fn1=函数(e){
    e、 目标。
    
    function f() { return "=>" }
    
        F.toString().replace(/\s+/g, '').indexOf(')=>')>=1
    
    /** Check if function is Arrow Function */
    const isArrowFn = (fn) => (typeof fn === 'function') && /^[^{]+?=>/.test(fn.toString());
    
    /* Demo */
    const fn = () => {};
    const fn2 = function () { return () => 4 }
    
    isArrowFn(fn)  // True
    isArrowFn(fn2) // False
    
    const isArrowFn = f => typeof f === 'function' && (/^([^{=]+|\(.*\)\s*)?=>/).test(f.toString().replace(/\s/, ''))
    
    const obj = {
        f1: () => {},
        f2 () {}
    }
    
    isArrowFn(obj.f1) // true
    isArrowFn(() => {}) // true
    isArrowFn((x = () => {}) => {}) // true
    
    isArrowFn(obj.f2) // false
    isArrowFn(function () {}) // false
    isArrowFn(function (x = () => {}) {}) // false
    isArrowFn(function () { return () => {} }) // false
    isArrowFn(Math.random) // false
    
    const isArrowFunction = obj => typeof obj === 'function' && obj.prototype === undefined;
    isArrowFunction(() => 10); // true
    isArrowFunction(function() {}); // false