一、划分
根据方法块(function的一对大括号),不包括for、while、if等语句块(es6的let、const解决了这一问题)。即JS所说的作用域即为函数作用域。
二、全局作用域
在最外面定义的变量或者在函数中没有用var定(不是重新赋值)的变量就具有全局作用域,在代码中任何地方都能访问,即所谓的全局变量,全局变量会绑定到window上。
var a = 'global'; //最外面var定义的变量
console.log(a);
function test(){
console.log(a); //在任何地方都可以调用
b = "global"; //没有用var定义的变量
}
test();
console.log(b);
三、变量局部作用域
如果一个变量在函数体内部申明,则该变量的作用域为这整个函数体,只在各自的函数体内起作用,在函数体外不可引用该变量,即所谓的局部变量。
function foo() {
var x = 1; //函数内部var定义的变量,作用域即为foo函数内部
return x + 1; //函数内部可随意调用
}
x = x + 2; // Uncaught ReferenceError: x is not defined 无法在函数体外引用变量x
四、作用域链
作用域链是js函数在创建的时候定义的,用于寻找到变量的一个索引。作用域链索引的内部规则是将函数自身的本地变量放在最前面,把自身的父级函数变量放在其次,再把高一级的函数的变量放在更后面,以此类推直到window全局对象为止。当需要查找一个变量时,js解释器会从作用域链去查找该变量,先从该函数的本地变量开始查找,如果没有,则在下一级作用域链进行查找,如果查找到相应变量则返回该变量,如果直到最后也没找到相应变量则返回undefined。简单说就是,当一个变量在当前作用域下找不到该变量的定义,js引擎会向外层作用域查找,一直如此知道最外层window对象。
function foo() {
var x = 1;
function bar() {
var y = x + 1; // bar作用域中无x,向外层foo查找
return y;
}
var z = y + 1; // ReferenceError! foo不可以访问bar的变量y!
}
全局变量和局部变量重名,局部作用域中局部变量会覆盖全局变量,离开后恢复。可用window.全局变量访问。
五、变量提升
所有变量的声明语句会被提升到当前变量作用域的顶部。先声明但未进行初始化。
function foo() {
var x = 'Hello, ' + y;
//不会报错,js提升了y变量的声明(即var y;提升到了开头),但未进行赋值,y为undefined
console.log(x);
var y = 'Bob';
}
foo(); //Hello, undefined