分类
全局作用域
函数作用域
块级作用域(ES6之后)
作用
隔离变量,不同作用域下同名变量不会有冲突
作用域与执行上下文
- 区别
– 除全局作用域之外,每个函数都会创建自己的作用域,作用域在函数定义时就已经确定了(即静态作用域)。而不是在函数调用时(即动态作用域)
– 全局执行上下文环境是在全局作用域确定之后,js代码执行之前创建
– 函数执行上下文环境是在调用函数时,函数体代码执行之前创建
– 作用域是静态的,只要函数定义好了就一直存在,且不会再变化
– 上下文环境是动态的,调用函数时创建,函数调用结束时上下文环境就会被释放 - 联系
– 上下文环境是属于所在作用域的
– 全局上下文环境属于全局作用域
– 函数上下文环境属于对应的函数作用域
作用域与执行上下文环境的关系
作用域链
- 理解
– 多个上下级关系的作用域形成的链,它的方向是从下向上的(从内到外)
– 查找变量时就是沿着作用域链来查找的 - 查找一个变量的查找规则
– 在当前作用域下的执行上下文中查找对应的属性,如果有直接返回,否则进入上一级作用域
– 在上一级作用域的执行上下文中查找对应的属性,如果有直接返回,否则进入更上一级作用域
– 再次执行2的相同操作,直到全局使用域,如果还找不到就抛出找不到的异常
var a = 1
function fn1() {
var b = 2
function fn2() {
var c = 3
console.log(c) // 找到当前作用域里执行上下文对象中的变量c
console.log(b) // 当前作用域未找到,继续向上查找.....找到b
console.log(a) // 当前作用域未找到,在全局作用域中的执行上下文对象中找到a
console.log(d) // 一直未找到,将报出错误
}
fn2()
}
作用域示意图
全局作用域->fn作用域->bar作用域,形成了一个作用域链
测试题
var x = 10;
function fn() {
console.log(x)
}
function show(f) {
var x = 20
f();
}
show(fn);
上面的代码将打印10
注意,函数是按作用域链的顺序查找使用的变量,而不是按执行上下文栈的顺序查找
var fn = function() {
console.log(fn)
}
fn()
var obj = {
fn2: function() {
console.log(fn2) // 改成this.fn2 或 obj.fn2 都可以正确执行
}
}
obj.fn2()
第一个fn() 将输出fn函数本身的代码
第二个obj.fn2()会报错,原因是函数执行时是按作用域链依次查找使用到的变量的,当在函数fn2 内部找不到fn2时,将会在全局作用域中查找,而全局作用域中,没有直接保存fn2变量,而是存在obj对象中,所以找不到