目录
写在最前
概念
为什么要用AST
Esprima
一个简单的AST例子
函数结构
变量声明语句和表达式语句
class声明和Function构造函数
箭头函数
参数结构
总结
首页 web前端 js教程 怎样获取JS函数参数名 ?用AST获取js函数参数名的方法分析

怎样获取JS函数参数名 ?用AST获取js函数参数名的方法分析

Sep 18, 2018 pm 03:03 PM
ast function javascript

本篇文章给大家带来的内容是关于怎样获取JS函数参数名 ?用AST获取js函数参数名的方法分析,有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。

写在最前

最近项目有个需求,获取函数参数名,听起来很简单,但有了ES6,参数和函数写法千奇百怪,在github上大概看了几个库,基本上都是正则,
对通用的写法能够覆盖,稍微越过边界,往往无法正确匹配。

于是就有了使用AST去进行覆盖查找的想法。

概念

抽象语法树(abstract syntax tree或者缩写为AST),或者语法树(syntax tree),是源代码的抽象语法结构的树状表现形式

为什么要用AST

通过AST,我们可以对代码进行查找,看起来好像正则表达式也可以做到,那么为什么要用AST而不用正则?

就说从函数获取参数名,夸张点,如果有以下表达式:

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){}
登录后复制

参数是[a,b,c,d,e,f,g,h]

你确定还想用正则去匹配参数名称吗...

AST是从代码的意义去编辑,而正则只能从代码的字面去编辑。

以上夸张的函数,使用AST去分析,可以很轻松获取它的参数名

Esprima

我们使用esprima,一个可以将Javascript代码解析成抽象树的库。

首先我们需要安装它:

npm install esprima

接着调用:

const esprima=require('require'')

接下来就是分析的时候了

一个简单的AST例子

先来个简单的例子:
function a(b){}

通过esprima解析后,生成结构图如下:

{
    "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"
}
登录后复制

思路:

1、FunctionDeclaration说明是一个函数表达式,进入params属性。

2、判断params中每一个的type是否为Identifier,在params属性下的Identifier就代表是参数。

3、找出name属性的值,结果为['b']。

根据以上思路,我们可以写出一个简单的获取参数的方法了。

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
}
登录后复制

测试一番,获取结果["b"],庆祝收工。

好吧,别高兴太早了,要知道函数的创建方法不下10种,而参数写法又有好几种...

以下是一部分的函数创建方法和参数写法

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){}})()")
登录后复制

有什么想法?如果你有发出"我K"的想法,那说明我这个装逼还算成功- -...

其实只需要分几种情况(很多写法的type都是一致的),就可以完全渗入到以上所有的参数对象内部,再进行参数获取就是循环+判断解决的事了。

由于篇幅问题,这里不一一分析,只是将AST分析树所用的type和一些注意点。

函数结构

变量声明语句和表达式语句

上面注释中let a=function(x=1){}和a=function(...x){}是两种意义。

其中let a=function(x=1){}指的是变量声明语句,

对应的type是VariableDeclaration,需要进入它的初始值init就可以获取到函数所在的语法对象,它的type是FunctionExpression函数表达式,再去params中查找即可。

变量声明语句:

├──VariableDeclaration....init
        ├──FunctionExpression.params
登录后复制

而a=function(...x){}是表达式语句,

对应的type是ExpressionStatement,需要进入它的表达式expression获取到表达式内部,这时我们要进入赋值表达式(type为AssignmentExpression)的右边(right属性),
获取函数所在的语法对象,它的type同样也是FunctionExpression函数表达式。

表达式语句:

├──ExpressionStatement.expression
        ├──AssignmentExpression.right
                ├──FunctionExpression.params
登录后复制

class声明和Function构造函数

class声明对应的type有ClassDeclaration(class xx{...})或者ClassExpression(let x=class{...}),他们一个是声明一个是表达式,处理方式是相同的,
进入对象内部,找到kind为constructor的对象,获取参数数据。

class声明语句:

├──ClassDeclaration...body...
        ├──{kind:constructor}
                ├──FunctionExpression.params
登录后复制

Function构造函数对应的type是NewExpression或者ClassExpression,参数在属性arguments内部,但是Function的参数都是字符串,
而且最后一个参数一定是函数内部语句,因此对于Function构造函数,就是对字符串进行处理。

Function构造函数

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

箭头函数

箭头函数type是ArrowFunctionExpression,也仅仅是名称不同,内部结构几乎一致。

函数结构的type就到此。

参数结构

参数的type有以下:

Identifier:最终我们需要获取的参数值的type

Property:当存在解构参数,例如[a,b] or {x,y}

ArrayPattern:存在解构参数并且是数组,例如[a,b]

ObjectPattern:存在解构参数并且是对象,例如{x,y}

RestElement:存在扩展运算符,例如(...args)

我们只需要设置一个递归循环,思路和上面一样,一层进入另一层,在内部进行查找。

总结

篇幅有限,就写这么多,接着做一个总结。

这篇讲的主旨只有1个,通过对AST树中每一个对象的type分析,type表示的是对应的代码的意义,也是代码的语义,例如

VariableDeclaration内部一定会有init,为什么,因为变量声明是有初始值的,如果你不设置,那么就为undefined

type远不止这次说的这么多,官网(或者Google)上有详细介绍。

以上是怎样获取JS函数参数名 ?用AST获取js函数参数名的方法分析的详细内容。更多信息请关注PHP中文网其他相关文章!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您听不到任何人,如何修复音频
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解锁Myrise中的所有内容
4 周前 By 尊渡假赌尊渡假赌尊渡假赌

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

如何使用WebSocket和JavaScript实现在线语音识别系统 如何使用WebSocket和JavaScript实现在线语音识别系统 Dec 17, 2023 pm 02:54 PM

如何使用WebSocket和JavaScript实现在线语音识别系统引言:随着科技的不断发展,语音识别技术已经成为了人工智能领域的重要组成部分。而基于WebSocket和JavaScript实现的在线语音识别系统,具备了低延迟、实时性和跨平台的特点,成为了一种被广泛应用的解决方案。本文将介绍如何使用WebSocket和JavaScript来实现在线语音识别系

WebSocket与JavaScript:实现实时监控系统的关键技术 WebSocket与JavaScript:实现实时监控系统的关键技术 Dec 17, 2023 pm 05:30 PM

WebSocket与JavaScript:实现实时监控系统的关键技术引言:随着互联网技术的快速发展,实时监控系统在各个领域中得到了广泛的应用。而实现实时监控的关键技术之一就是WebSocket与JavaScript的结合使用。本文将介绍WebSocket与JavaScript在实时监控系统中的应用,并给出代码示例,详细解释其实现原理。一、WebSocket技

如何利用JavaScript和WebSocket实现实时在线点餐系统 如何利用JavaScript和WebSocket实现实时在线点餐系统 Dec 17, 2023 pm 12:09 PM

如何利用JavaScript和WebSocket实现实时在线点餐系统介绍:随着互联网的普及和技术的进步,越来越多的餐厅开始提供在线点餐服务。为了实现实时在线点餐系统,我们可以利用JavaScript和WebSocket技术。WebSocket是一种基于TCP协议的全双工通信协议,可以实现客户端与服务器的实时双向通信。在实时在线点餐系统中,当用户选择菜品并下单

如何使用WebSocket和JavaScript实现在线预约系统 如何使用WebSocket和JavaScript实现在线预约系统 Dec 17, 2023 am 09:39 AM

如何使用WebSocket和JavaScript实现在线预约系统在当今数字化的时代,越来越多的业务和服务都需要提供在线预约功能。而实现一个高效、实时的在线预约系统是至关重要的。本文将介绍如何使用WebSocket和JavaScript来实现一个在线预约系统,并提供具体的代码示例。一、什么是WebSocketWebSocket是一种在单个TCP连接上进行全双工

JavaScript和WebSocket:打造高效的实时天气预报系统 JavaScript和WebSocket:打造高效的实时天气预报系统 Dec 17, 2023 pm 05:13 PM

JavaScript和WebSocket:打造高效的实时天气预报系统引言:如今,天气预报的准确性对于日常生活以及决策制定具有重要意义。随着技术的发展,我们可以通过实时获取天气数据来提供更准确可靠的天气预报。在本文中,我们将学习如何使用JavaScript和WebSocket技术,来构建一个高效的实时天气预报系统。本文将通过具体的代码示例来展示实现的过程。We

简易JavaScript教程:获取HTTP状态码的方法 简易JavaScript教程:获取HTTP状态码的方法 Jan 05, 2024 pm 06:08 PM

JavaScript教程:如何获取HTTP状态码,需要具体代码示例前言:在Web开发中,经常会涉及到与服务器进行数据交互的场景。在与服务器进行通信时,我们经常需要获取返回的HTTP状态码来判断操作是否成功,根据不同的状态码来进行相应的处理。本篇文章将教你如何使用JavaScript获取HTTP状态码,并提供一些实用的代码示例。使用XMLHttpRequest

javascript中如何使用insertBefore javascript中如何使用insertBefore Nov 24, 2023 am 11:56 AM

用法:在JavaScript中,insertBefore()方法用于在DOM树中插入一个新的节点。这个方法需要两个参数:要插入的新节点和参考节点(即新节点将要被插入的位置的节点)。

如何在JavaScript中获取HTTP状态码的简单方法 如何在JavaScript中获取HTTP状态码的简单方法 Jan 05, 2024 pm 01:37 PM

JavaScript中的HTTP状态码获取方法简介:在进行前端开发中,我们常常需要处理与后端接口的交互,而HTTP状态码就是其中非常重要的一部分。了解和获取HTTP状态码有助于我们更好地处理接口返回的数据。本文将介绍使用JavaScript获取HTTP状态码的方法,并提供具体代码示例。一、什么是HTTP状态码HTTP状态码是指当浏览器向服务器发起请求时,服务

See all articles