作用域: 域表示的就是范围,即作用范围,就是一个名字在什么地方可以被使用,什么时候不能使用;
在c,java 等语言中 采用块级的作用范围 { var num=123; { console.log(num);// 123 } } console.log(num); //报错
在js中采用词法作用域:
所谓词法(代码)作用域,就是代码在编写过程中体现出来的作用范围,代码一旦写好,不用执行,作用范围就已经确定好了,这个就是所谓词法作用域
在js中词法作用域规则:
- 函数允许访问函数外的数据
- 整个代码结构中只有函数可以限定作用域
- 作用规则首先使用提升规则分析
- 如果当前作用规则中有名字了,就不考虑外面的名字
var num=123; function foo(){ console.log(num); } foo(); //123 分析:预解析 num 和foo(),foo函数体和函数名绑定,执行代码:num=123;打印num的值 ,输出123;
if(false){ var num=123; } console.log(num); //undefined 分析:预解析一个num,执行代码:内存中已经存在num了,所以if体不执行,也就不赋值,所以打印为undefined
var num=123; function foo(){ var num=456; function func(){ console.log(num); } func(); } foo(); //456 console.log(num);//123 分析:外部的num没有被修改,内部的作用域的foo的num是456,又因为func里没有num 只能去他的第一个外层找,所以是456
作用域链
*可以发现只有函数可以制造作用域结构,那么只要有代码,至少有一个作用域,即全局作用域
*凡是代码中有函数,那么这个函数就构成另一个作用域,如果函数中还有函数,那么在这个作用域中就又可以诞生一个作用域,那么将这样的所有的作用域列出来,可以有一个结构:函数内指向函数外的链式结构
绘制作用域链的步骤:
- 看整个全局是一条链,即顶级链,记为0级链
- 看全局作用域中有什么成员声明,就以方格的形式绘制到0级链上
- 再找函数,只有函数可以限制作用域,因此从函数中引出新链,标记为1级链
- 然后在每一个1级链中再次往复刚才的行为
变量的访问规则
- 首先看变量在第几条链上,在该链上看是否有变量的定义与赋值,如果有直接使用,
- 如果没有到上一级链上找(n-1级链),如果有直接找,停止继续查找
- 如果还没有 再次往上找….,直到全局链(0 级),还没有就是报错 is not defined
- 注意,切记同级的链不可混合查找
作用域链上如何分析代码
- 在分析代码的时候切记从代码的运行进度上来分析,如果代码给变量赋值了,一定要标记到图中,
- 如果代码比较复杂,可以在图中描述代码的内容,有时甚至需要将原型图与作用图合并分析