0%

javascript作用域,上下文环境,自由变量以及闭包

javascript 的作用域

  • 在 javascript 中, 没有块级的作用域 (反人类), 所以为了避免误解, 最好不要在块作用域内声明变量
1
2
3
4
5
var i = 10;
if i > 1 {
var name = "levon";
}
console.log(name);//levon
  • 除了全局作用域, 只有函数才可以创建作用域
  • 作用域有上下级关系, 最大的目的就是隔离变量, 不同作用域下同名变量也不会冲突
1
2
3
4
5
6
7
8
9
var a = 10; //window.a = 10; 全局作用域

function fn(){
var a = 100; //fn 作用域

function bar(){
var a = 1000; //bar 作用域
}
}

javascript 的作用域和执行上下文环境

  • 作用域只是一个“地盘”,一个抽象的概念。
  • 如果要查找一个作用域下某个变量的值,就需要找到这个作用域对应的执行上下文环境,再在其中寻找变量的值。
  • 作用域中变量的值是在执行过程中产生的确定的,而作用域却是在函数创建时就确定了。
  • 同一个作用域下,不同的调用会产生不同的执行上下文环境,继而产生不同的变量的值。

作用域和上下文环境绝对不是一回事儿

  • 作用域:

首先,它很抽象。另外除了全局作用域,只有函数才能创建作用域。创建一个函数就创建了一个作用域,无论你调用不调用,函数只要创建了,它就有独立的作用域,就有自己的一个“地盘”。

  • 上下文环境:

可以理解为一个看不见摸不着的对象(有若干个属性),虽然看不见摸不着,但确实实实在在存在的,因为所有的变量都在里面存储着,要不然咱们定义的变量在哪里存?

另外,对于函数来说,上下文环境是在调用时创建的,这个很好理解。拿参数做例子,你不调用函数,我哪儿知道你要给我传什么参数?

  • 两者之间的关系:

一个作用域下可能包含若干个上下文环境。有可能从来没有过上下文环境(函数从来就没有被调用过);有可能有过,现在函数被调用完毕后,上下文环境被销毁了;有可能同时存在一个或多个(闭包)。

1
2
3
4
5
6
7
8
9
10
11
12
var x = 100;
function fn(x){
return function(){
console.log(x);
}
}

var f1 = fn(5);
var f2 = fn(10);

f1();//5
f2();//10

上面代码一个fn作用域下同时存在两个上下文环境。可以理解作用域是静态的组织结构,而上下文环境是动态的调用。

自由变量依赖静态作用域

  • 在 A作用域中使用的变量 x, 却没有在 A作用域中声明(即在其他作用域中声明的), 那么对于 A作用域来说, x 就是一个自由变量.
1
2
3
4
5
var x = 10;
function fn(){
var b = 20;
console.log(x + b); //这里的 x 就是一个自由变量
}
  • 那么去哪里取自由变量的值? 要到 创建 包含自由变量 函数 的那个 作用域 中取值——是“创建”,而不是“调用”. 一定要切记其实这就是所谓的“静态作用域”。

  • 那么在执行 fn 的时候, x 取值去哪里取呢? 答案是要到创建fn函数的那个作用域中取——>无论fn函数将在哪里调用。(anywhere call, only find on create)

  • 如果静态作用域找不到怎么办? 此时就需要一级一级跨作用域一直找到全局作用域

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var a = 10;

function fn(){
var b = 20; // 如果此处没有20, b 就会找到200

function bar(){
console.log(a + b);// a 一直跨到全局作用域找到, b 直接在 fn 作用域找到,
}

return bar;
}

var x = fn();
var b = 200;
x();

来看一道题:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var x = 10;

function show(){

function fn(){
console.log(x);
}

var x = 20;

(function(){
var x = 30;
fn();
})();
}

show();//答案是20, 想想为什么

闭包其实就是上下文环境不销毁

闭包一般只有两种情况——函数作为返回值,函数作为参数传递。

1
2
3
4
5
6
7
8
9
10
11
12
13
function fn(){
var max = 10;

return function bar(x){
if (x > max){
console.log(x);
}
};
}

var f1 = fn();
var max = 100;
f1(15);
  • 全局上下文环境准备, global —> f1 = undefined, max = undefined
  • 执行到 var f1 = fn(); 进入fn()执行上下文环境. fn —> max = 10
  • fn() 函数返回, 本来要销毁上下文的max, 但是 bar 函数却引用了这个max, 因此这个max不能被销毁,销毁了bar函数中的max就找不到值了。所以fn()上下文环境保留. fn —> max = 10
  • var max = 100; global —> f1 = fn(), max = 100
  • f1(15) 进入fn执行上下文环境, max 是10, x 是15, 输出15
  • 执行完毕进入全局上下文环境
给作者打赏,可以加首页微信,咨询作者相关问题!