关于js编译的一些特性 | 青训营笔记
这是我参与 第四届青训营 笔记创作活动的的第4天
由于本人用javascript时间挺短的(八月份开始接触),因此本篇主要总结一些比较特殊,比较奇怪的一些样例。
作用域
全局作用域和局部作用域
在整个script标签起作用的为全局作用域,只在函数内部起作用的为局部作用域。
全局变量和局部变量
用过其它编程语言的都会知道,特别是java,对于变量的作用域的定义是特别严格,这里简单提一下javascript的全局变量和局部变量:看下面的代码:
<script>
var num_out = 10; //全局变量
function a(){
num = 1011; //全局变量(函数内部直接声明,没有声明)
var num_in = 100; //局部变量,于外面的num毫无关系
}
console.log(num_in)
//全局变量直到浏览器关闭才销毁
</script>
在上面的代码中,num_out为全局变量,函数a可以随意的访问全局变量。
num_in为局部变量,只在函数a这块作用域中才有效,在函数外调用则会报错,因为局部变量在函数结束后则会自动销毁。
tips:未声明变量也不会报错,且该变量默认为全局变量。
块级作用域
在java中:
public class Main{
public static void main(String [] args){
if(true){
int temp = 1;
print(temp);
}
print(temp);
}
}
这种代码在java是肯定过不了的,因为在if这个块级作用域中,temp不会在块级作用域之外生效。但在javascript中这种情况却允许存在。
例如在javascript:
<script>
if(2 > 3){
var num = 10;
}
console.log(num)
</script>
这样子却不会报错,因为在es6(标准)之前,javascript没有块级作用域,解决该问题可将var改为let。
javascript中的
let是ES6新增的关键字,let允许我们声明一个作用域或被限制在块级中的变量、语句或者表达式。let声明的变量只能是全局或者整个函数块的。
作用域链
先看下面的代码:
<script>
//js中采取链式查找的方式,向上查找存在的变量,若在上级不存在,则再向上查找
var num2=20;
function a(){
var num2=10;
function b(){
console.log(num2);
}
b();
}
a();
</script>
打开后台,结果显示10。js中查找变量的方法是从里向外找,不是从外向里。
Javascript预解析
javascript是一种解释型的脚本语言,相比其他语言例如c++/c的先编译后执行,Javascript与python差不多,边解释边运行。
javascript引擎在运行js时需要分两步,预解析和代码执行,代码执行不用说,主要讲预解析。
预解析其实做的工作就是把js代码中的所有var和function声明提升到当前作用域的最前面,然后再进行代码执行。也就是变量提升和函数提升,预解析步骤不做赋值和调用函数的操作。详细请看下面的代码:
<script>
var a = 18;
f1();
function f1(){
var b = 9;
console.log(a);
console.log(b);
var a = '123';
}
</script>
上面的代码运行结果可能出乎意料,我们对其进行分析,模仿js引擎的操作,对其进行预解析,结果如下:
<script>
var a;
function f1(){
var b;
var a;
b = 9;
console.log(a);
console.log(b);
a = '123';
}
a = 18;
f1();
</script>
运行结果:undefined, 9。
总结
在我看来,js主要需要注意的是块作用域和预解析的问题,块作用域可以用let代替var去避免变量的误用,而预解析则需要考虑写代码时的顺序问题,毕竟运行结果在代码量大的时候不可能一行一行去分析,我们写代码还是需要有逻辑上的考量,避免运行结果的出乎意料。