JS问题:一个页面有两个script标签,这如何理解?

钟鼓楼
  • 284
<script>alert(a)</script> // 报错:a is not defined
<script>var a=12;alert(a)</script>//但报错后没有停止执行,弹了12

如果换一下位置

<script>var a=12;alert(a)</script>
<script>alert(a)</script> //代码正常

请问两个script标签该如何去理解?为什么第一个script报错了,但程序还能继续向下走,执行第二个script标签。这和平时写JS代码出错时:报错-停止执行,两者处理机制不同?谢谢!

<script>alert(a)</script> // 报错:a is not defined
<script>var a=12;alert(a)</script>//但报错后没有停止执行,弹了12
回复
阅读 18.8k
12 个回答
梦禅
  • 3.2k
✓ 已被采纳

JavaScript解释器在执行脚本时,是按块来执行的。通俗地说,就是浏览器在解析HTML文档流时,如果遇到一个<script>标签,则JavaScript解释器会等到这个代码块都加载完后,先对代码块进行预编译,然后再执行。执行完毕后,浏览器会继续解析下面的HTML文档流,同时JavaScript解释器也准备好处理下一个代码块。

由于JavaScript是按块执行的,所以如果在一个JavaScript块中调用后面块中声明的变量或函数就会提示语法错误。第一端代码就是这情况。

虽然说,JavaScript是按块执行的,但是不同块都属于同一个全局作用域,也就是说,块之间的变量和函数是可以共享的。 这也是第二段代码为什么可以访问前一个块里的a的原因。

来自网络资源:

step 1. 读入第一个代码块。

step 2. 做语法分析,有错则报语法错误(比如括号不匹配等),并跳转到step5。

step 3. 对var变量和function定义做“预编译处理”(永远不会报错的,因为只解析正确的声明)。

step 4. 执行代码段,有错则报错(比如变量未定义)。

step 5. 如果还有下一个代码段,则读入下一个代码段,重复step2。

step6. 结束。

javascript运行机制之执行顺序详解
【朴灵评注】JavaScript 运行机制详解:再谈Event Loop

边城
  • 55k

看楼主的说法

html<script>alert(a)</script> // 报错:a is not defined
<script>var a=12;alert(a)</script>//但报错后没有停止执行,弹了12

如果合并

html<script>
alert(a);    // 弹 undefined
var a = 12;
alert(a);    // 弹 12
</script>

这相当于

html<script>
var a;
alert(a);
a = 12;
alert(a);
</script>

所以,合并之后和合并之前的效果是不一样的

最后解释一下为什么合并前后效果不一样……我猜的:

<script> 标签每加载完一个就会解释执行里面的代码,所以在只加载了第1段 <script> 的时候,还没有申明 a,报错。

而合并之后,所有代码都加载了,按 JavaScript 的规范,是把申明前置了的,所以 var a 会被放在最前面执行,就不报错了。

各个script标签里的代码会分开执行,
所以第一个标签里报错后第二个仍然会执行。

换个位置正常是因为两个标签的代码都在全局作用域下,
第一个标签声明变量a后,第二个标签就能找到它了。

qianjiahao
  • 8.4k

script只是划分了js的执行环境,其实看可以看做 是 几个分段执行的 js执行环境

另外,第一种报错,是因为你在未给a赋值的时候使用a,所以报undefined。

蚝油牛肉盖浇饭
  • 1k

你可以理解成浏览器把两端javascript的代码合并了

<script>
var a=12;
alert(a);
alert(a)
</script>

@边城狂人 我合并的是题主第二段代码

标签的的顺序影响了js的执行顺序,因为js是从上往下执行的,调换了顺序,结果就不一样了。和是不是在一个script标签无关系。

这个应该和js不存在块级作用域有关,就比如:
function test(){console.log(a); var a = 1; console.log(a);}
test();-----undefined 1

function test(){console.log(a); var b = 1; console.log(b);}
test();----ReferenceError: a is not defined

可以在网上查下js块级作用域。

JS 是顺序执行的,先执行上一个,然后执行下一个,当执行这一句的时候,并没有定义a变量


<script>alert(a)</script>

但是执行这一句的时候<script>var a=12;alert(a)</script>/是定义了a变量的,所以会弹出。
在JS中报错后还是会执行的

这个跟JS没有关系,是浏览器的原因。

在浏览器解析引擎看来,<script>只是一个标签,它需要像对待其他标签一样解析<script>中的内容,也就是代码文本,然后将其提交给JS引擎解析和执行。只不过<script>标签更为特殊一点,浏览器会严格控制提交的顺序,保证先定义的<script>先执行,即使后面的<script>内容先下载完也必须等待。这就导致了楼主你所看到的现象——虽然所有<script>标签中的代码处于同一个作用域,但由于提交给JS引擎的顺序不同,所以JS引擎在执行前一段代码时,无法看到后一段代码的内容,也就无法完成“跨标签”代码的变量定义提升了。

很简单,你可以理解为php的notice错误和ERROR错误,错误级别不同,效果也不同,如果你是语法错误之类的致命错误,js会停止后续执行。

kikong
  • 19.1k
<script>alert(a)</script> // 报错:a is not defined
<script>var a=12;alert(a)</script>//但报错后没有停止执行,弹了12

等价于以下代码块
====>

<script>
    alert(a);
    var a=12;
    alert(a);
</script> 

因为变量提升的关系
等价于

<script>
    var a;
    alert(a);//a is not defined,没有出错,存在变量a,只是变量值没有定义
    a=12;//a 赋值
    alert(a);//a=12
</script> 

效果和以下代码不同

<script>
    alert(b);//b未定义 Uncaught ReferenceError: b is not defined 引用错误
    //以下代码不会被执行
    var a=12;
    alert(a);
</script> 
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
宣传栏