手机版

详细介绍JavaScript执行顺序

时间:2021-11-12 来源:互联网 编辑:宝哥软件园 浏览:

在从JavaScript引擎的解析机制探究JavaScript的工作原理之前,我们先用一个更生动的例子来说明页面中JavaScript代码的执行顺序。如果说JavaScript引擎的工作机制因为属于底层行为而深刻,那么JavaScript代码的执行顺序就更加生动,因为我们可以直观的感受到这个执行顺序。当然,JavaScript代码的执行顺序比较复杂,在深入到JavaScript语言之前有必要对其进行分析。1.1按照HTML文档流的顺序执行JavaScript代码。首先,读者应该知道,浏览器中HTML文档的解析过程是这样的:浏览器按照文档流从上到下逐步解析页面结构和信息。作为嵌入式脚本,JavaScript代码也应该被看作是HTML文档不可分割的一部分,所以加载时JavaScript代码的执行顺序也是根据脚本标签脚本的出现顺序来决定的。例如,如果您浏览下面的文档页面,您将看到代码是从上到下一步一步解析的。复制代码代码如下: script altert(' top script ');/scripthtmlheadscripttalert('头脚本');/script title/title/headbodyscripttalert('页面脚本');/script/body/htmlscriptalert('底部脚本');/script如果通过script标记脚本的src属性导入外部JavaScript文件脚本,它也将按照其语句出现的顺序执行,执行过程是文档加载的一部分。不会因为是外部JavaScript文件而推迟执行。例如,将上述文档中标题和正文区域的脚本移动到外部JavaScript文件,然后通过src属性导入。继续预览页面文档,您将看到相同的执行顺序。按如下方式复制代码: script altert(' top script ');/scripthtmlheadlescript src=' http://www . JB 51 . net/head . js '/script title/title/headlebodyscript src=' http://www.jb51.net/body.js'/script/body/htmlscriptalert '('底部脚本');/script1.2预编译与执行顺序的关系在Javascript中,函数是Javascript的第一种类型。当我们写下一个函数时,我们只是创建了一个类型为function的实体。就像我们可以这样写一样:复制代码如下:函数hello(){ alert(' hello ');} Hello();varHello=function(){ alert(' Hello ');} Hello();都一样。但是当我们修改函数时,我们会发现奇怪的问题。复制的代码如下:脚本类型=' text/JavaScript '函数hello(){ alert(' hello ');} Hello();function Hello(){ alert(' Hello World ');} Hello();/script我们将看到Hello World连续输出两次的结果。不是我们想象中的哈啰和哈啰世界。这是因为Javascript并不是完全按顺序解释和执行的,而是会在解释之前“预编译”一次。在预编译过程中,将首先执行已定义的函数,并创建所有var变量。默认值未定义,以提高程序的执行效率。也就是说,上面的代码实际上是由JS引擎预编译成这样的形式:复制的代码如下: script type=' text/JavaScript ' varhello=function(){ alert(' hello ');} Hello=function(){ alert(' Hello World ');} Hello();hello();/script我们从上面的代码中可以清楚地看到,函数既是数据也是变量,我们还可以给“函数”赋值(重新赋值)。当然,为了防止这样的情况,我们也可以这样做:复制代码如下:脚本类型=' text/JavaScript '函数hello(){ alert(' hello ');} Hello();/script script type=' text/JavaScript ' function Hello(){ alert(' Hello World ');} Hello();/script这样,程序被分成了两个部分,JS引擎不会把它们放在一起。当JavaScript引擎解析脚本时,它将在预编译期间处理所有声明的变量和函数。

做到以下几点:1。在执行之前,做一些类似于“预编译”的事情:首先,在当前执行环境中创建一个活动对象,并将var声明的变量设置为活动对象的属性,但此时这些变量的赋值是未定义的,function定义的函数也被添加为活动对象的属性,它们的值正好是函数的定义。2.在解释执行阶段,当一个变量需要解析时,首先会从当前执行环境的活动对象中进行搜索;如果没有找到,并且执行环境的所有者具有原型属性,则从原型链中搜索;否则,将根据范围链进行搜索。在诸如var a=.将分配相应的变量(注意:变量的分配在解释执行阶段完成,如果变量在此之前使用,其值将是未定义的)。因此,当JavaScript解释器执行以下脚本时,不会报错:复制代码如下: alert(a);//返回值undefinedvar a=1;警报(a);//返回值1因为变量声明是在预编译过程中处理的,所以在执行过程中所有代码都可以看到它们。但是,您也可以看到,当您执行上述代码时,提示值是未定义的,而不是1。这是因为变量的初始化过程发生在执行时,而不是预编译时。在执行阶段,JavaScript解释器根据代码序列进行解析。如果变量没有在前面的代码行中赋值,JavaScript解释器将使用默认值undefined。由于变量A在第二行被赋值,第三行代码将提示变量A的值是1而不是未定义。同样,在下面的示例中,在声明函数之前调用该函数是合法的,并且可以正确解析,因此返回值为1。复制代码如下: f();//调用函数,返回值1 function f(){ alert(1);}但是,如果函数定义如下,JavaScript解释器会提示语法错误。复制代码如下: f();//调用函数,返回语法错误var f=function(){ alert(1);}这是因为上例中定义的函数只将变量f赋值为值,所以JavaScript解释器只能在预编译期间处理声明的变量f,而变量f的值只能在执行期间按顺序赋值,这自然会导致语法错误,说明找不到对象f。告别部分示例:复制的代码如下: script type=' text/JavaScript '/* func是预编译过程中窗口环境中活动对象中的一个属性,值为函数,覆盖未定义的值*/alert(func);//func func(){ alert(' hello!')}var func='这是一个变量' func(){alert('hello!)}/*在执行过程中遇到对“这是一个变量”*/alert(func)的var重新分配;//这是一个变量/脚本复制代码如下: script type=' text/JavaScript ' var name=' feng ';func func(){/*首先在func环境中将名称赋值为undefined,然后在执行过程中在func环境中查找活动对象的name属性。此时预编译值未定义,所以输出未定义,而不是feng */alert(name);//未定义的var name=' JSF ';警报(名称);//JSF } func();警报(名称);//feng/script虽然变量和函数可以在文档中的任何地方声明,但是在所有JavaScript代码之前声明全局变量和函数,并对变量进行初始化和赋值是一个很好的习惯。在函数中,变量先声明,然后引用。1.3分块执行JavaScript代码。代码块是由脚本标签分隔的代码段。例如,以下两个脚本标记表示两个JavaScript代码块。复制的代码如下:script//JavaScript代码块1var a=1/scriptscript//JavaScript代码块2 function f(){ alert(1);}/script JAVAScript解释器分块执行脚本。一般来说,如果浏览器在解析HTML文档流时遇到脚本标签,JavaScript解释器会等到代码块加载完毕,然后预编译代码块再执行。

执行后,浏览器将继续解析下面的HTML文档流,JavaScript解释器将准备好处理下一个代码块。因为JavaScript是分块执行的,所以如果在JavaScript块中调用后面块中声明的变量或函数,会出现语法错误的提示。例如,当JavaScript解释器执行以下代码时,会提示语法错误,显示变量A未定义,找不到对象F。复制代码如下:script//JavaScript代码块1 alert(a);f();/scriptscript//JavaScript代码块2var a=1;函数f(){ alert(1);}/script虽然JavaScript是分块执行的,但是不同的块属于同一个全局范围,也就是说块之间的变量和函数是可以共享的。1.4借助事件机制改变JavaScript执行顺序。因为JavaScript以块的形式处理代码,并遵循HTML文档流的解析顺序,所以在上面的示例中,您会看到这样的语法错误。但是,当加载文档流时,如果再次访问文档流,则不会出现这种错误。例如,如果将访问变量和函数的代码放在页面初始化事件函数的第二个代码中,就不会有语法错误。复制的代码如下:script//JavaScript代码块1window.onload=function(){ //页面初始化事件处理程序alert(a);f();}/scriptscript//JavaScript代码块2var a=1;函数f(){ alert(1);}/script为了安全起见,我们通常允许在页面初始化后执行JavaScript代码,这样可以避免网络速度对JavaScript执行的影响,也可以避免HTML文档流对JavaScript执行的限制。请注意,如果一个页面中有多个windows.onload事件处理程序,则只有最后一个有效。为了解决这个问题,所有脚本或调用函数都可以放在同一个onload事件处理程序中。例如,复制代码如下:Window。onload=function(){ f1();F2();F3();}这样,只需调整onload事件处理程序中调用函数的顺序,就可以改变函数的执行顺序。除了页面初始化事件,我们还可以通过各种交互事件来改变JavaScript代码的执行顺序,比如鼠标事件、键盘事件和时钟触发器。详情请参阅第14章。1.5 JavaScript输出脚本的执行顺序在JavaScript开发中,经常使用文档对象的write()方法来输出JavaScript脚本。那么这些动态输出脚本是如何执行的呢?例如,复制代码如下: document . write(' script type=' text/JavaScript ' ');document . write(' f();');document . write(' function f(){ ');document . write(' alert(1);');document . write(' } ');document . write('/script ');运行上面的代码,我们会发现document.write()方法首先将输出脚本字符串写入脚本所在的文档位置,浏览器在解析脚本所在的文档内容后继续解析document.write()的输出内容,然后依次解析后续的HTML文档。也就是说,JavaScript脚本输出的代码字符串在输出后会立即执行。请注意,document.write()方法输出的JavaScript脚本字符串必须同时放在脚本标签输出中,否则JavaScript解释器在页面文档中会显示为普通字符串,因为它无法识别这些合法的JavaScript代码。例如,下面的代码将显示JavaScript代码,而不是执行它。复制代码如下: document . write(' f();');document . write(' function f(){ ');document . write(' alert(1);');document . write(');');但是通过document.write()方法输出脚本并执行存在一定的风险,因为不同的JavaScript引擎执行的顺序不同,不同的浏览器在解析时也存在bug。首先,找不到document.write()方法导入的外部JavaScript文件中声明的变量或函数。例如,请看下面的示例代码。

复制了以下代码: document . write(' script type=' text/JavaScript ' src=' http://www . JB 51 . net/test . js '/script ');document . write(' script type=' text/JavaScript ' ');document . write(' alert(n);');//IE提示找不到变量n document . write(“/script”);警报(n1);//所有浏览器都会提示找不到变量n的外部JavaScript文件(test.js)的代码如下:复制代码的代码如下: var n=1;在不同的浏览器中测试,会发现提示语法错误,找不到变量n。也就是说,如果这个代码块中document.write()方法输出的脚本中导入的外部JavaScript文件中包含的变量在JavaScript代码块中被访问,就会显示语法错误。同时,如果在IE浏览器中,不仅在脚本中,在输出脚本中,都会提示导入到外部JavaScript文件中的输出变量找不到(表达式有点长,比较费解,不理解的读者可以尝试运行上面的代码来理解)。其次,不同的JavaScript引擎对于输出外部导入脚本的执行顺序略有不同。例如,请看下面的示例代码。复制了以下代码: script type=' text/JAVAScript ' document . write(' script type=' text/JAVAScript ' src=' http :3358 Shao zhong.com/test1 . js '/script ');document . write(' script type=' text/JavaScript ' ');document . write(' alert(2);')document . write(' alert(N2);');document . write('/script ');/script script type=' text/JavaScript ' alert(n ^ 3);/script外部JavaScript文件(test1.js)的代码如下所示。复制代码如下: var n=1;警报(n);IE浏览器中的执行顺序如图1-6所示。

图1-6 IE 7浏览器的执行顺序和提示的语法错误与DOM标准中的IE浏览器不同,没有语法错误。图1-7显示了火狐3.0浏览器中的执行顺序。

图1-7:火狐3浏览器的执行顺序和提示的语法错误,解决了不同浏览器执行顺序不同和可能出现的bug。我们可以将使用输出脚本导入的所有外部文件放在单独的代码块中,这样根据上面描述的JavaScript代码块的执行顺序就可以避免这个问题。比如上面的例子,可以设计如下:复制的代码如下: Script Type=' text/JavaScript ' document . write(' Script Type=' text/JavaScript ' src=' http://www . JB 51 . net/test1 . js '/Script ');/script script type=' text/JavaScript ' document . write(' script type=' text/JavaScript ' ');document . write(' alert(2);' ) ;//提示2 document . write(' alert(n ^ 2);' );//提示3 document . write('/script ');警报(n3);//tip 4/script script type=' text/JavaScript ' alert(n 4);//Tip 5/script,让上面的代码可以在不同的浏览器中依次执行,输出顺序为1、2、3、4、5。问题的原因是输出和导入的脚本与当前的JavaScript代码块之间的矛盾。如果单独输出,就不会有冲突。

版权声明:详细介绍JavaScript执行顺序是由宝哥软件园云端程序自动收集整理而来。如果本文侵犯了你的权益,请联系本站底部QQ或者邮箱删除。