JavaScript的作用域和变量提升
看了众多的书籍和文章后,决定自己来写一遍关于作用域的知识点来巩固一下。
作用域
作用域在编程语言中,它是控制着变量与参数的可访问性和生命周期。
作用域这个东西呢,可以假设它是一个采集工人,专注于收集和维护所有声明的标识符(变量),并且将标识符组成一系列的查询,并实现一套规则来管理标识符,确定执行环境(执行上下文)对标识符的使用权限。
function foo () { var a = 1, b = 3;
console.log(c) // 报错,变量c没有定义,父级函数不能获取子函数中的变量 // a => 1, b => 3 function bar () { var c = 5, d = 7; a += b + c; // 可访问父级函数的a,b变量,并修改变量a的值 } // a => 1, b => 3 bar();
// a => 9, b => } foo();
块级作用域
在JS函数中的var声明,其作用域是函数体的全部,在ES6之前并没有块级作用域的说法,在ES5中只有全局作用域和函数作用域。
大多数像C语言的语言都拥有块级作用域,就是在一个代码块中(在一对花括号中的语句)定义的所有变量在代码块的外部是不可访问的,定义在代码块中的变量会在代码块执行完毕后会释放掉。
在ES6中的新特性:let、const提供了块级作用域。
if (true) { let a = 1; } console.log(a)// Uncaught ReferenceError: a is not defined
变量提升(Hoisting)
直觉上会认为JavaScript代码在执行时是由上到下一行一行执行的。但实际上并不完全正确,有一种特殊情况会导致这个假设是错误的。
考虑下面的代码
a = 2; var a; console.log(a) // a => 2
这种写法固然是不推荐的,但它却正确地输出出来,到底是为什么呢。
再看看一下代码
console.log(a) // a => undefined var a = 2
搞明白这个问题,要了解引擎和编译器的机制。
引擎在解释JavaSript代码之前首先会对其进行编译,编译阶段中的一部分工作就是找到所有的声明,并用合适的作用域将它们关联起来。
因此,正确的思路是:在编译的时候,变量和函数在内的所有声明都会在任何代码被执行之前被处理。
当然,用ES6中的let就不会出现这个问题了,科科~