我们知道JavaScript代码执行的时候有一个概念叫做作用域,当我们访问一个变量的时候,会先看看当前作用域有没有定义这个变量,如果没有就会沿着作用域链向上一直寻找到全局作用域,如果作用域链上都没有该变量的定义的话就会抛出一个Uncaught ReferenceError: xx is not defined的错误。在实现Simple语言解释器的时候,我参照了JavaScript作用域的概念实现了一个叫做Environment的类,我们来看看Evironment类的实现:
// lib/ast/node/FunctionDeclaration.ts class FunctionDeclaration extends Node { ...
// 函数执行的时候,如果存在调用函数的实例,该实例会被当做参数传进来,例如a.test(),a就是test的这个参数 call(args: Array<any>, callerInstance?: any): any { // 函数执行时传进来的参数如果少于声明的参数会报错 if (this.params.length !== args.length) { thrownewError('function declared parameters are not matched with arguments') }
// 这是实现闭包的重点,函数执行时的父级作用域是之前函数被定义的时候记录下来的父级作用域!! const callEnvironment = new Environment(this.parentEnv) // 函数参数进行初始化 for (let i = 0; i < args.length; i++) { const argument = args[i] const param = this.params[i]
对于大多数前端开发者来说JavaScript可谓是我们最熟悉的编程语言了,它十分强大可是有些语言特性却十分难以理解,例如闭包和this绑定等概念往往会让初学者摸不着头脑。网上有很多诸如《你看完这篇还不懂this绑定就来砍我》之类的文章来为大家传道解惑。可是在我看来这些文章大多流于表面,你读了很多可能还是会被面试官问倒。 那么如何才能彻彻底底理解这些语言特性,从而在面试的时候立于不败之地呢?在我看来要想真的理解一样东西,最好的途径就是实现这样东西,这也是西方程序员非常喜欢说的learning by implementing。例如,你想更好地理解React,那么最好的办法就是你自己动手实现一个React。因此为了更好地理解JavaScript的语言特性,我就自己动手实现了一个叫做Simple的JavaScript语言解释器,这个解释器十分简单,它基于TypeScript实现了JavaScript语法的子集,主要包括下面这些功能: