作用域
JavaScript中作用域是指可访问变量的集合(对象、函数也是变量)。
作用域规定了程序在执行时该如何查找变量,也就是确定当前执行代码对变量的访问权限。
作用域分为:词法作用域(静态作用域)、动态作用域。
那么什么是静态作用域,动态作用域呢?
静、动态作用域
JavaScript中采用的是词法作用域(静态作用域)。
静态作用域:函数的作用域在函数定义时就决定了。
动态作用域:函数的作用域在函数调用时才决定。
下面是一个例子能更好区分两者:
var value = 5;
function f1(){
console.log(value);
}
function f2(){
var value = 10;
f1();
}
f2(); //5
可以看到最后的结果输出是:5
分析如下:
假设JavaScript中采用的是静态作用域,函数f1在定义时作用域就已经决定了,即执行函数f1()时,先在函数内部查找是否有变量value,如果没有则在上一层作用域查找,此时全局变量value就是所查找结果,即value=5,输出结果就是:5
假设JavaScript中采用的是动态作用域,函数f1执行的是,先从函数内部查找是否有变量value,如果没有就查找 f2 函数的作用域,发现 f2 函数局部作用域中有value变量,即输出结果应为:10
已经介绍过JavaScript采用的是静态作用域,所以这段代码最后执行的结果是:5
再看下面一个例子:
var name = 'zsl';
function foo(){
var name = 'zc';
function bar(){
return name;
}
return bar();
}
console.log(foo()); //zc
var name = 'zsl';
function foo(){
var name = 'zc';
function bar(){
return name;
}
return bar;
}
console.log(foo()());//zc
由结果看见上面两个结果都是zc
分析如下:
JavaScript 函数的执行用到了作用域链,这个作用域链是在函数定义的时候创建的。嵌套的函数 bar() 定义在这个作用域链里,其中的变量 name一定是局部变量,不管何时何地执行函数 bar(),这种绑定在执行 bar() 时依然有效。这个例子也更好的解释了JavaScript采用的是静态作用域。
作用域链
当代码在一个环境执行时,会创建变量对象的一个作用域链。
那么什么作用域链呢?
作用域链:我的理解就是当函数执行时会首先在局部作用域中查找相关变量,如果没有则就再去上一层(父级)作用域中查找,然后逐级向上层作用域中查找,直到到达作用域最顶端(全局作用域),这种一层一层的关系,就构成了作用域链。
下面是一个例子:
var name = 'zsl';
var bodys = 'good';
function foo1(){
var name = 'zc';
var age = 18;
function foo2(){
var lives = 'learning';
function foo3(){
var height = 180;
function foo4(){
var st = 3;
console.log(st);
console.log(height);
console.log(lives);
console.log(age);
console.log(name);
console.log(bodys);
}
return foo4();
}
return foo3();
}
return foo2();
}
foo1();
//3
//180
//learning
//18
//zc
//good
注意:当代码在执行时是沿着作用域链一级一级地查找,查找过程始终是从作用域链的前端开始然后逐级向上查找,直到作用域链最顶端(全局作用域)为止,如果还是找不到相关变量,通常会导致错误发生。
作用域链的前端:始终都是当前执行的代码所在环境的变量对象。
作用域链的作用:是保证对执行环境有权访问的所有变量和函数的有序访问。