48740


JavaScriptの関数の引数名を取得することはできるのでしょうか?

[code]

    function my_func(foo, bar) {
        return foo * bar
    }
    
[/code]

上のような`my_func`関数があったとして、

[code]

    my_func.args_name //  ["foo", "bar"]
    
[/code]

この`args_name`のように引数の名前を配列などで取ることはできないのでしょうか?

正規表現を使えばできなくはないのですが、デフォルト引数などを使ったりするとさらに複雑になってしまうのでなるべく避けたいです。


CC BY-SA 4.0
2018-09-26T14:40:40.063
48736
2018-09-26T15:29:46.120
5246
question
javascript
JavaScriptの関数の引数名を取得する


参考としてですが、質問で言った正規表現での方法を載せておきます。  
ただし、この方法では関数にデフォルト値を設定するとうまく動かなくなります。

[code]

    function my_func(foo, bar) {
        return foo * bar
    }
    
    let func_str = String(my_func);
    let arg_names = /\((.+)\)/.exec(func_str)[1].split(","); // ["foo", "bar"]
    console.log(arg_names);
[/code]


CC BY-SA 4.0
2018-09-26T14:47:24.613
48737
2018-09-26T14:47:24.613
5246
48736
answer


残念ながら、関数の引数名を取得する簡単な方法は用意されていません。

質問者さんのおっしゃるように関数を文字列に変換してそこから情報を取得するしかありませんが、正規表現では確かにデフォルト値があるときに太刀打ちするのが難しくなります。

それを乗り越える一つの方法は、例えば[acorn](https://github.com/acornjs/acorn)のような
**JavaScriptパーサー** を用いて、関数を表す文字列を再度構文解析して関数の情報を得ることです。

とりあえずacornを使って関数の引数名を取得するコードは以下のとおりです。

[code]

    const acorn = require('acorn');
    
    function my_func(foo, bar = 3, baz, {hoge}) {
        return foo * bar;
    }   
    
    // my_funcを文字列化する
    const my_func_str = my_func.toString();
    
    // acorn.parseで構文解析する
    const parsed = acorn.parse(my_func_str);
    
    // 正しくパースされていることを確認
    console.assert(parsed.type === 'Program');
    
    // 関数宣言が認識されていることを確認
    const funcDecl = parsed.body[0];
    console.assert(funcDecl.type === 'FunctionDeclaration');
    
    // 一応名前が合っている確認
    console.assert(funcDecl.id.name === 'my_func');
    
    // 引数の名前の配列を作成
    const argNames = funcDecl.params.map(mapArgToName);
    
    console.log(argNames); // ['foo', 'bar', 'baz', 'no name']
    
    // 関数引数のオブジェクトを関数名にマップする関数
    // （適当に書いたので処理漏れがあるかもしれません）
    function mapArgToName(argObject) {
        switch (argObject.type) {
            case 'Identifier': {
                return argObject.name;
            }
            case 'AssignmentPattern': {
                return mapArgToName(argObject.left);
            }
        }
        return 'no name';
    }  
    
[/code]

これで一応目的のことは可能かと思いますが、ソースコードをいちいち構文解析するのは決して軽い処理ではありません。本当にこんなことをしてまで関数の引数名を取得する必要があるのかはよく考えたほうがよいかと思います。

* * *

余談ですが、JavaScriptの引数においては「引数名」は必ず存在するとは限りません。例えば以下の関数の第一引数は名前がありません。上の例ではこれは`'no
name'`にしています。

[code]

    function func({foo, bar}) { return foo * bar; }
    
[/code]


CC BY-SA 4.0
2018-09-26T15:18:34.187
48740
2018-09-26T15:29:46.120
2018-09-26T15:29:46.120
30079
30079
48736
answer