ES5:var
ES6:let、const
var怪异变量
首先我们要明确,var是一个块变量也叫作用域变量,如果它放到一个函数中,在函数外调用应该是失败的,在不用var a=1,这样进行定义而变成a=2,时则这个变量就变成了全局变量,如
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title></title> </head> <body> <script> function var1() { var a = 3 } function var2() { b = 4 } var1() var2() console.log(b) console.log(a) </script> </body> </html>
在上述代码中,正常定义的a是报错显示a没有被定义,但是没有定义的b=4则怪异的变成了全局变量,一方面我们可以使用严格模式来定义这个函数,则会解决这个怪异问题。‘use strict’
同时它还有变量提升的怪异之处,我们知道,在script当中是按顺序来进行初次加载和调用的,如果我们在script全局作用域中打印出来一个a变量,那我们一定要先定义a变量再打印才能出现结果,否则就会报错,但在怪异变量中,我们如果先打印后定义不会报错,会显示undefined,就是变量已经被定义但是没有被赋值,是因为在ES当中
console.log(a);var a=1;
被等价成
var a;console.log(a);a=1;
也就是把所有的变量都拉到当前作用域的顶部,此外,多次使用var声明同一个变量也没有问题。
这就是var变量的怪异之处。而正是因为这些怪异之处,导致在ES6当中,诞生了let和const两个关键词。
let关键词
let和var的区别是,它没有var那些怪异的‘处事风格’,同时它是一个块作用域,而var是一个函数作用域
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title></title> </head> <body> <script> function let1() { if (true) { let a=1; } console.log(a) } function var1(){ if(true){ var a=1; } console.log(a) } var1();let1() </script> </body> </html>
具体表现为,它在if-else,switch,for等定义的变量,在这些条件语句外则无法被调用,每个条件语句对它来说都是一个块,而var,只要在函数中任何地方定义,就可以在任何地方被调用。
同时在let中,也不会变量提升,在定义let变量前,不能被调用,也称为“暂时性死区”。
全局声明
在全局作用域中声明的let变量不会成为window对象的属性,而var定义的变量会,具体表现在,window.属性名出现具体值还是出现的是undefined。
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title></title> </head> <body> <script> var a=1; console.log(window.a) let b=1; console.log(window.b) </script> </body> </html>
const常量
const在初始化时必须被赋初值且不能被修改,但如果定义的是对象,修改对象中的属性的具体值,则不会报错且能修改。因为const声明的限制只是在它指向变量的引用。而具体的属性的值在修改的时候,并没有改变属性变量所在地址,所以这种改变是被允许的,但是不能改变它的属性名。
上述例子中,我们发现当我们在const常量对象中修改属性的内容可以被修改,如果利用正则表达式修改某个属性名,则不会被修改成功。如果把const变成let则可以修改成功。
在大多数时候,为了避免出现代码怪异的情况,大多数开发者会选择用let和const来代替var关键词作为定义变量的主要选择,同时这样也会提升代码质量,让代码不会出现重复定义的问题和全局/作用域问题。实际const,let,var的这些属性和特征往底层实现还是要看基础的存储空间堆栈那里,这里就不多赘述了。