JavaScript ES6: 矢印関数、組み込み関数、通常の関数をテストしますか? 質問する

JavaScript ES6: 矢印関数、組み込み関数、通常の関数をテストしますか? 質問する

Harmonyのスリム矢印関数を通常の関数と区別するエレガントな方法はありますか?そして組み込み関数?

ハーモニーウィキ次のように述べています。

アロー関数は組み込み関数と似ており、プロトタイプがないそして[[Construct]]内部メソッド。したがってnew (() => {})はTypeErrorをスローしますが、それ以外は矢印は関数のようです

つまり、次のような矢印関数をテストできます。

!(()=>{}).hasOwnProperty("prototype") // true
!(function(){}).hasOwnProperty("prototype") // false

ただし、テストはまたは などtrueの組み込み関数に対しても を返します。setTimeoutMath.min

ソースコードを入手して確認すると、Firefox では動作します"native code"が、信頼性や移植性はあまり高くないようです (他のブラウザ実装、NodeJS / iojs)。

setTimeout.toSource().indexOf("[native code]") > -1

小さなGitHubプロジェクトノードは矢印関数です関数のソースコードに対する RegExp チェックに依存していますが、これはあまりきれいではありません。

編集:私は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;

ベストアンサー1

信じようと信じまいと...

関数の文字列表現に「=>」が存在するかどうかをテストすることが、おそらく最も信頼性の高い方法です (ただし、100% ではありません)。

明らかに、あなたが言及した 2 つの条件、つまりプロトタイプ プロパティの欠如と の欠如のどちらに対してもテストすることはできません。これは、( 、など)[[Construct]]が欠落しているホスト オブジェクトまたは組み込みオブジェクトで誤検知を引き起こす可能性があります。[[Construct]]Math.floorJSON.parse

Function.prototype.toStringただし、関数表現に「=>」が含まれているかどうかを確認するには、古き良き方法を使用できます。

さて、私はいつもに対してFunction.prototype.toString(いわゆる関数の逆コンパイル)は、実装に依存し、歴史的に信頼性が低いため、Javascript における関数の逆コンパイルの状態)。

しかしES6は実際にはルールを強制しようとする(少なくとも)組み込み関数と「ユーザー作成」(適切な言葉がないため)関数が表現される方法です。

  1. Type(func)がObjectで、組み込み関数オブジェクトか[[ECMAScriptCode]]内部スロットを持つ、 それから

    a. 関数の実装依存の文字列ソースコード表現を返す。表現以下の規則に従う必要があります

...

toString 表現の要件:

  • 文字列表現は、FunctionDeclaration FunctionExpression、GeneratorDeclaration、GeneratorExpession、ClassDeclaration、ClassExpressionの構文を持つ必要があります。矢印関数オブジェクトの実際の特性に応じて、MethodDefinition、または GeneratorMethod になります。

  • 表現文字列内の空白、行末記号、セミコロンの使用と配置は実装に依存します。

  • オブジェクトが ECMAScript コードを使用して定義され、返された文字列表現が MethodDefinition または GeneratorMethod の形式ではない場合は、元のオブジェクトの作成に使用された語彙コンテキストと同等の語彙コンテキストで eval を使用して文字列を評価すると、機能的に同等の新しいオブジェクトが生成される表現にする必要があります。その場合、返されたソース コードでは、元の関数のソース コードで自由に記述されなかった変数を自由に記述してはなりません。これらの「余分な」名前が元々スコープ内にあったとしてもです。

  • 実装がこれらの基準を満たすソース コード文字列を生成できない場合は、eval が SyntaxError 例外をスローする文字列を返す必要があります。

関連する部分をハイライトしました。

矢印関数には内部[[ECMAScriptCode]](14.2.17「矢印関数の評価」から追跡できます)があります。関数作成関数の初期化)。

つまり、彼らはArrowFunction構文:

ArrowFunction[In, Yield] :
  ArrowParameters[?Yield] [no LineTerminator here] => ConciseBody[?In]

つまり、Function.prototype.toStringの出力には => が含まれている必要があります。

明らかに、「=>」が ArrowParameters の後に続き、FunctionBody 内に存在するだけではないことを確認する必要があります。

function f() { return "=>" }

信頼性に関しては、この動作は現時点ではどのエンジンでもサポートされているわけではないこと、また、ホスト オブジェクトの表現が何らかの理由で (仕様の努力にもかかわらず) 間違っている可能性があることに留意してください。

おすすめ記事