当前位置: 首页 > 科技观察

JavaScript预解析过程原来是这个东西

时间:2023-03-13 04:05:31 科技观察

解释一般来说,Javascript代码的执行包括两个过程:预解析过程和逐行解释过程。在逐行解释代码之前,Javasript引擎需要对代码进行预处理。预解析处理的工作主要是提升变量和为变量分配内存。具体过程是在各个作用域中查找var声明的变量、函数定义和命名函数(函数参数)。找到他们之后,给他们分配内存,给他们初值。预解析设置的初始值是:对于var声明的变量,初始值为undefined;对于函数定义,变量名就是函数名,函数变量的初始值就是函数定义本身;对于命名参数,如果函数调用时没有指定参数值,则命名参数的初始值为未定义,如果函数调用指定了参数值,则命名参数的初始值为指定的参数值。注意:对于同时声明和赋值变量的语句,例如:vara=9,Javascript引擎在处理时,将语句拆分为两条语句:vara和a=9,其中vara在预解析阶段进行处理,a=9为赋值表达式,在逐行解释阶段进行赋值。所以在预解析的时候,不管变量声明时有没有赋值,变量的初始值都是undefined。1、预解析的时机(1)、浏览器在加载标签时,会使用javascript引擎对标签对:查找函数定义内和函数体外所有var声明的变量,并为它们分配内存并设置初始值。对于同名的var变量和function变量,只会分配一个栈内存。但是,在堆内存中,会为函数变量的初始值分配内存。给变量赋初值时,函数变量的初值优先于var变量的初值,同级函数变量,后定义的函数优先于前定义的函数。所以当var变量名与函数变量名相同时,如果一开始变量在内存中的值是undefined,那么内存中变量的初始值将替换为函数变量的值;否则,变量的初始值保持不变。对于同名的函数变量,后面定义的函数将替换前面定义的函数。(2)当遇到函数时,每对标签中的代码会在预解析后立即逐行解释。在解释代码的过程中,如果遇到函数调用,此时会先在函数作用域内进行预解析过程,预解析过程之后再执行函数代码。函数作用域中的预解析规则是:查找命名函数、所有var变量和函数定义,并在函数作用域中为它们分配内存并设置初始值。对于同名的var变量、命名参数和函数变量,栈内存只会分配一次,但会在堆内存中为函数变量的初始值分配内存。给变量赋初值时,函数变量的值具有最高的优先级,其次是命名参数值。所以命名参数名与var变量名相同,变量在内存中的值就是参数值;如果命名参数名与函数变量名相同或var变量名与函数变量名相同,则变量在内存中的值为函数变量值。2、页面包含多个标签时的预解析当页面包含多个标签时,javascript引擎会根据标签出现page,从上到下,预解析和逐行解释每个标签对之间的脚本代码块。每个标签对之间的代码预解析是全局的,调用函数时发生的函数代码预解析是针对函数作用域的。需要注意的是,在预解析过程中得到的变量初值会被赋值给表达式(表达式中有=、+=、-=、*=、/=、++、--等操作)逐行解释代码(符号语句)修改的过程。示例让我们通过几个示例详细了解一下。预解析变量优先级示例:弹出框的结果为:1.弹出内容:(1)这一行的结果为:functiona(){alert(4);}3.弹出内容:(2)这一行的结果是:37内容:(3)这一行的结果是:6上面的运行结果就是预解析和行的阶段处理的结果-逐行解释。当Javascript引擎遇到标签时,按照代码出现的顺序开始预解析:首先预解析注2处的var变量a,为其分配内存,赋值它的初始值为“未定义”;然后预分析注4处的函数变量a,发现这个变量和已经分配内存的var变量同名,所以不再给函数变量a分配栈内存,只分配堆内存存放函数定义,同时将栈内存中变量a的值改为函数变量functiona(){alert(2);};的初始值然后预解析注5处的var变量a,它与前面预解析得到的函数变量a同名,所以该变量将不再分配内存。由于函数变量值优先于var变量值,所以注5处的var变量aundefined的初始值不会修改内存变量的函数定义值;最后预解析注6处的函数变量a,发现它与内存中的变量a同名,不再为其分配内存,而是在堆中分配内存,用于存放location处的函数定义6.由于后面定义的函数比前面定义的函数具有更高的优先级,所以此时将内存中变量a的函数定义值改为functiona(){alert(4);}。因此,最终内存中变量a的初始值为functiona(){alert(4)};。至此,预解析完成。然后逐行阅读代码。在逐行解释代码阶段,先解释注释1处的代码,此时会去内存中查找变量a。如果找到,则读取变量a的值并输出到警告对话框;如果没有找到,它将报告一个未定义的错误。上面预解析的结果是内存中存在变量a,其值为functiona(){alert(4);}。注2处的代码是一个赋值表达式:a=3。执行这段代码后,内存中变量a的值会被修改为“3”。所以当执行注释3处的代码时,从内存中读取的值为“3”。注4定义了一个函数,执行时会跳出函数定义,什么都不做。注释5处的代码是一个赋值表达式:a=6。执行完这行代码后,内存中变量a的值就会被修改为“6”。注6是另外一个函数定义,这里不再解释。最后,执行注释7处的代码,并读取值“6”。