变量声明
ES5中的var和function
es5中只有两种声明: var 和 function。 两者本质一样完全一样,只是var表明是一个变量,function在表明是一个变量的基础上,还特别标记这个变量的值是一段代码,所以function其实是一个带值的声明,var是不带值的声明。 所以,理论上可以将所有是 function 声明的地方直接替换为 var。 当位于等号右边时,就不是语句声明,而只是一个表达式 如 var a = function b(){...} b不会被提升,且b的作用域只在其函数体中。 var A = class B{} 也是一样的道理。 注意:- var aa = function (){...} 这不是函数声明,而是函数表达式。
- 变量提升时,var 与 function 有点不一样, var只提升变量的声明,不提升变量的值, function是直接提升声明和值。
console.log(aa); // 输出的值是 函数,因为此时function aa(){} 已经提升,且还没有被赋值为9
var aa = 9;
function aa(){
console.log(555);
}
console.log(aa); // 输出的值是9,因为 function aa 是整体提升
// 执行的过程是:
// 先提升 var aa; 此时 aa是undefined
// 再提升 function aa(){...}, 此时 aa已经有值,是一个函数
// 最后,再执行 aa = 9; 此时 aa的值是9
// 等价于以下代码
var aa;
function aa(){
console.log(555);
}
console.log(aa);
aa = 9;
console.log(aa);
- 不带值的声明提升是不会影响(先提升的)变量的当前值的
function aa(){ // 最先提升
console.log(6666);
}
function aa(){ // 第2个提升,因为有值,所以会覆盖前一个提升的aa的值
console.log(555);
}
var aa; // 这里的变量提升,因为没有带值,不会对前面已经提升的有值的aa变量产生影响
console.log(aa); // 结果是输入555的函数aa
ES6中的let、const、var、function
作用域
花括号标记代码块,圆括号标记表达式。 在js中,花括号括起来的整体直接解析为代码块,而圆括号括起来的内容,直接解析为表达式。{console.log(88);} // 花括号,解析为代码块
{x: 3, b: 4} // 报错,因为花括号解析为代码块
function(){ console.log(3333); } // 报错,因为没有被赋值给其它变量,所以解析为一个函数, 但该函数没有有名字,相当于声明一个没有名字的变量,故语法错误
({x: 3, b: 4}) // 正确,圆括号解析为表达式,返回一个对象
(function(){ console.log(3333); }) // 正确,圆括号解析为表达式,返回一个函数
(function(){ console.log(3333); })() // 立即调用这个函数
(function(){ console.log(3333); }()) // 立即调用这个函数,圆括号中的函数被识别为一个表达式,则可以不要名字(如果被识别为函数声明,则必须要有名字)
for(let i=0; i<3; i++){} // 注意,for循环中虽然也有圆括号,但这个圆括号是作为for语句的一部分而存在的,跟前面说的那种圆括号的含义完全不一样。这种情况还包括 while循环 if语句等结构
如何识别一个作用域
最外层的代码、函数体
es6中新增: for循环体、while循环体、if中的花括号、单独存在的花括号,均是一个独立的作用域。
另外,es6还有两种特殊情况:
- for循环的圆括号,整个圆括号位于一个独立的作用域中,循环体是这个作用域的子作用域。
- 函数声明或函数表达式中的圆括号,位于一个独立的作用域中,函数体是其子作用域。