Home  >  Article  >  Web Front-end  >  How to get JS function parameter name? Analysis of the method of using AST to obtain js function parameter names

How to get JS function parameter name? Analysis of the method of using AST to obtain js function parameter names

不言
不言Original
2018-09-18 15:03:582803browse

What this article brings to you is how to get the JS function parameter name? The analysis of the method of obtaining js function parameter names using AST has certain reference value. Friends in need can refer to it. I hope it will be helpful to you.

Written at the front

There is a requirement in a recent project to get function parameter names. It sounds very simple, but with ES6, parameters and functions are written in all kinds of strange ways. I looked at a few on github. Libraries are basically regular.
can cover common writing methods. However, if it crosses the boundary slightly, it often cannot be matched correctly.

So I came up with the idea of ​​using AST to perform coverage search.

Concept

Abstract syntax tree (abstract syntax tree or abbreviated as AST), or syntax tree (syntax tree), is a tree-like representation of the abstract syntax structure of the source code

Why use AST

Through AST, we can search the code. It seems that regular expressions can also do it, so why use AST instead of regular expressions?

It means getting the parameter name from the function, exaggerating, if there is the following expression:

function x(a=5,b="a",c=function(x=1,y){console.log(x=function(i=8,j){})},d={x:1,y:2,z:'x=6'},e=x=>7,f=['3=5','x.1','y,2',1],g=(x,y)=>{let z=(i,j=6)=>{}},h){}

The parameters are [a,b,c,d,e,f,g,h]

Are you sure you still want to use regular expressions to match parameter names...

AST is edited from the meaning of the code, while regular expressions can only be edited from the literal meaning of the code.

The above exaggerated function can be analyzed using AST, and its parameter name can be easily obtained

Esprima

We use esprima, which can parse Javascript code into an abstract tree library.

First we need to install it:

npm install esprima

Then call:

const esprima=require('require'')

Then it’s time to analyze

A simple AST example

Let’s take a simple example first:
function a(b){}

Passed After esprima is parsed, the structure diagram is generated as follows:

{
    "type": "Program",
    "body": [
        {   // 这个type表示这是一个函数表达式
            "type": "FunctionDeclaration",
            "id": {
                "type": "Identifier",
                "name": "a"
            },
            "params": [
                {
                    // 参数数组内的Identifier代表参数
                    "type": "Identifier",
                    "name": "b"
                }
            ],
            "body": {
                "type": "BlockStatement",
                "body": []
            },
            "generator": false,
            "expression": false,
            "async": false
        }
    ],
    "sourceType": "script"
}

Ideas:

1. The FunctionDeclaration description is a function expression, enter the params attribute.

2. Determine whether the type of each params is Identifier. The Identifier under the params attribute represents a parameter.

3. Find the value of the name attribute. The result is ['b'].

Based on the above ideas, we can write a simple method to obtain parameters.

function getParams(fn){
  // 此处分析的代码必须是字符串
  let astEsprima=esprima.parseScript(fn.toString())
  let funcParams = []
  let node = astEsprima.body[0]
  // 找到type,进入params属性
  if (node.type === "FunctionDeclaration") funcParams = node.params
  let validParam=[]
  funcParams.forEach(obj=>{
    if(obj.type==="Identifier")
      validParam.push(obj.name)
  })
  return validParam
}

Test it, get the result ["b"], and celebrate the end of the work.

Okay, don’t be too happy. You must know that there are no less than 10 ways to create functions, and there are several ways to write parameters...

The following are some of the function creation methods and Parameter writing method

function a(x){}

// 注意:第二条和第三条在AST中意义不同
let a=function(x=1){}

a=function(...x){}

let a=([x]=[1])=>{}

async function a(x){}

function *a(x){}

class a{
constructor(x){}
}

new Function ('x','console.log(x)')

(function(){return function(x){}})()

eval("(function(){return function(a,b){}})()")

Any ideas? If you have the idea of ​​​​uttering "I K", it means that my pretense is quite successful - -...

In fact, it only needs to be divided into several situations (the types of many writing methods are the same), It can be completely penetrated into all the above parameter objects, and then obtaining parameters is a matter of loop judgment.

Due to space issues, we will not analyze them one by one here, but only the types used in the AST analysis tree and some attention points.

Function structure

Variable declaration statement and expression statement

In the above comments, let a=function(x=1){} and a=function(...x ){} has two meanings.

let a=function(x=1){} refers to the variable declaration statement.

The corresponding type is VariableDeclaration. You need to enter its initial value init to get the location of the function. The syntax object, its type is FunctionExpression function expression, and then search it in params.

Variable declaration statement:

├──VariableDeclaration....init
        ├──FunctionExpression.params

And a=function(...x){} is an expression statement,

The corresponding type is ExpressionStatement, you need to enter it The expression expression is obtained inside the expression. At this time, we need to enter the right side (right attribute) of the assignment expression (type is AssignmentExpression).
Get the syntax object where the function is located. Its type is also a FunctionExpression function expression.

Expression statement:

├──ExpressionStatement.expression
        ├──AssignmentExpression.right
                ├──FunctionExpression.params

class declaration and Function constructor

The type corresponding to the class declaration is ClassDeclaration(class xx{...}) or ClassExpression(let x =class{...}), one of them is a declaration and the other is an expression, and the processing method is the same.
Enter the object, find the object with kind as constructor, and obtain the parameter data.

Class declaration statement:

├──ClassDeclaration...body...
        ├──{kind:constructor}
                ├──FunctionExpression.params

The type corresponding to the Function constructor is NewExpression or ClassExpression, and the parameters are inside the property arguments, but the parameters of Function are all strings,
and the last parameter It must be a statement inside the function, so for the Function constructor, it processes the string.

Function constructor

├──NewExpression.arguments
        ├──{value:<String>}
         ---->对字符串进行处理,分割参数

Arrow function

The arrow function type is ArrowFunctionExpression, only the name is different, and the internal structure is almost the same.

That’s it for the type of function structure.

Parameter structure

The types of parameters are as follows:

Identifier: The type of parameter value we finally need to obtain

Property: When there is a deconstructed parameter, For example [a,b] or {x,y}

ArrayPattern: Destructuring parameters exist and are arrays, such as [a,b]

ObjectPattern: Destructuring parameters exist and are objects, such as { x,y}

RestElement: There are expansion operators, such as (...args)

We only need to set up a recursive loop. The idea is the same as above, one layer enters another layer, Look inside.

Summary

The space is limited, so I’ll just write this much and then make a summary.

There is only one main purpose of this article. Through type analysis of each object in the AST tree, type represents the meaning of the corresponding code and the semantics of the code. For example,

VariableDeclaration must have internal There is init, why? Because the variable declaration has an initial value. If you don't set it, it will be undefined.

type is much more than what I have said this time. There is a detailed introduction on the official website (or Google).

The above is the detailed content of How to get JS function parameter name? Analysis of the method of using AST to obtain js function parameter names. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn