作者回复: 我先来解释下页面在含有JavaScript的情况下DOM解析流程,然后再来解释你这个问题。
当从服务器接收HTML页面的第一批数据时,DOM解析器就开始工作了,在解析过程中,如果遇到了JS脚本,如下所示:
<html>
<body>
极客时间
<script>
document.write("--foo")
</script>
</body>
</html>
那么DOM解析器会先执行JavaScript脚本,执行完成之后,再继续往下解析。
那么第二种情况复杂点了,我们内联的脚本替换成js外部文件,如下所示:
<html>
<body>
极客时间
<script type="text/javascript" src="foo.js"></script>
</body>
</html>
这种情况下,当解析到JavaScript的时候,会先暂停DOM解析,并下载foo.js文件,下载完成之后执行该段JS文件,然后再继续往下解析DOM。这就是JavaScript文件为什么会阻塞DOM渲染。
我们再看第三种情况,还是看下面代码:
<html>
<head>
<style type="text/css" src = "theme.css" />
</head>
<body>
<p>极客时间</p>
<script>
let e = document.getElementsByTagName('p')[0]
e.style.color = 'blue'
</script>
</body>
</html>
当我在JavaScript中访问了某个元素的样式,那么这时候就需要等待这个样式被下载完成才能继续往下执行,所以在这种情况下,CSS也会阻塞DOM的解析。
所以这时候如果头部包含了js文件,那么同样也会暂停DOM解析,等带该JavaScript文件下载后,便开始编译执行该文件,执行结束之后,才开始继续DOM解析。
作者回复: 完全没问题,这个可以做参考答案!
作者回复: 下面是关于同名变量和函数的两点处理原则:
1:如果是同名的函数,JavaScript编译阶段会选择最后声明的那个。
2:如果变量和函数同名,那么在编译阶段,变量的声明会被忽略
作者回复:
ES规定函数只不能在块级作用域中声明,
function foo(){
if(true){
console.log('hello world');
function g(){ return true; }
}
}
也就是说,上面这行代码执行会报错,但是个大浏览器都没有遵守这个标准。
接下来到了ES6了,ES6明确支持块级作用域,ES6规定块级作用域内部声明的函数,和通过let声明变量的行为类似。
规定的是理想的,但是还要照顾实现,要是完全按照let的方式来修订,会影响到以前老的代码,所以为了向下兼容,个大浏览器基本是按照下面的方式来实现的:
function foo(){
if(true){
console.log('hello world');
var g = function(){return true;}
}
}
这就解释了你的疑问,不过还是不建议在块级作用域中定义函数,很多时候,简单的才是最好的。
作者回复: 对 是这样的,下面是关于同名变量和函数的两点处理原则:
1:如果是同名的函数,JavaScript编译阶段会选择最后声明的那个。
2:如果变量和函数同名,那么在编译阶段,变量的声明会被忽略。
作者回复: 对
作者回复: 先是生成字节码,然后解释器可以直接执行字节码,输出结果。 但是通常Javascript还有个编译器,会把那些频繁执行的字节码编译为二进制,这样那些经常被运行的函数就可以快速执行了,通常又把这种解释器和编译器混合使用的技术称为JIT
作者回复:
你也可以理解为涉及失误,因为设计之初的目的就是想让网页动起来,JavaScript创造者Brendan Eich并没有打算把语言设计太复杂。
所以只引入了函数级作用域和全局作用域,一些快级作用域都被华丽地忽略掉了。
这样如果变量或者函数在if块,while块里面,因为他们没有作用域,所以在编译阶段,就干脆把这些变量和函数提升到开头,这样设计语言的复杂性就大大降低了,但是这也埋下了混乱的种子。
随着JavaScript的流行,人们发现问题越来越多,中间的历史就展开了,最终推出了es6,在语言层面做了非常大的调整,但是为了保持想下兼容,就必须新的规则和旧的规则都同时支持,这样也导致了语言层面不必要的复杂性。
虽然JavaScript语言本身问题很多,但是它已经是整个开发生态中的不可或缺的一环了,因此,不要因为它的问题多就不想去学它,我认为判断要学不学习一门语言要看所能产生的价值,JavaScript就这样一门存在很多缺陷却是非常有价值的语言。
作者回复: 需要通过 var x 声明才会在编译期间提升
作者回复: 是的,变量环境中只保存一个
作者回复: 很赞
作者回复: 记住一点就行:函数只有在调用的时候才会被编译。
作者回复: 调用的时候,08节有介绍
作者回复: 需要的,因为不管是否缓存了,都需要执行JS
作者回复: 没问题
作者回复: 不过第二个语句仅仅是赋值操作,函数并没有执行,所以不会输出2的