一 JS的作用域
在ES5中,没有块级作用域,JS的作用域分为函数作用域和全局作用域两种。
在上面的代码中,变量color存在于if语句中,但是在if语句的外面能正确打印出color的值,所以color变量存在于全局作用域中。
在这个例子中,同时打印color1和color2变量,因为color1存在于全局变量中,所以color1的值能正确打印,而color2变量是在函数getColor中,所以在函数外面打印时报错,这是因为color2的作用域是getColor函数作用域。
在ES6中,新增了let和const,这两个类型的变量只存在于块级作用域中,并且不存在变量提升。
在if语句中将 var 换成 let ,在if语句外面打印变量color则报错,因为用let和const声明的变量作用域是块级作用域if。
二 JS中的作用域链
执行环境是JS中很重要的一个概念,执行环境定义了变量或者函数有权利访问的其他数据,决定了他们各自的行为。这些它有权利访问的数据都保存在一个叫变量对象的对象中。
通俗的理解就是假如我写了一段JS代码,他可以放在浏览器中运行,也可以放在node中运行,浏览器环境和node环境就叫做执行环境。如果代码中还有一段函数,那在执行这个函数的时候,它可能会在浏览器执行环境下再新建一个小的空间容器充当这个函数的执行环境。所以一般有很多个执行环境,每个环境中有个对象存储这个执行环境中可访问的变量和函数等,这个对象就叫做变量对象。
当代码在一个环境中执行时,会创建变量对象的一个作用域链。作用域链就是执行环境中变量对象中变量和函数访问的顺序。举还是上面的例子,一段代码中有函数和变量,函数里面也包含变量和函数。作用域链就是定义一个函数的执行环境以及它的父级和祖父级执行环境的顺序。如果要查找一个变量,将会按照作用域链一级级向上寻找搜索。
var color = red;
function changeColor(){
var anotherColor = "red";
function swapColor(){
var tempColor = anotherColor;
anotherColor = color;
color = tempColor;
}
swapColor();
}
changeColor();
在上面的代码中,共涉及到3个执行环境。全局环境、changeColor局部环境、swapColor局部环境。
在swapColor中可以访问changeColor和window执行环境中的变量。但是反过来就不行。
内部环境可以通过作用域链访问所有的外部环境,但是外部环境不可以访问内部环境中的任何变量和函数。这些环境的访问顺序是线性有次序的。
上面例子中getColor中没有color变量,所以向上查找到全局作用域中的color,并返回。
延长作用域链就是在作用域链的前端增加一个变量对象。有两种方法可以实现:
with语句、try-catch语句的catch块。
在ES6中let和const所在的块也是延长作用域链的一种。
三 结语
最近在理清一些前端中基础知识,发现概念不清晰阻碍了自己写出优秀的代码,解决问题的能力不是记不清楚细节的借口,要专精于自己的职业和工作才能不迷茫,更厉害。