作用域
词法作用域
作用域
域表示的就是范围,即作用范围
就是一个名字在什么地方能使用,在什么地方不能使用
块级作用域
块级别的作用范围
// 在 c , java 等编程语言中,下面的语法报错 { var num = 123; // 应该用int , 这里是伪代码 { console.log(num); // 123 } console.log(num); // 报错 }
在 js 中采取词法作用域
词法(代码)作用域,就是代码在编写过程中体现出来的作用范围,代码一旦写好,不用执行,他的作用范围就已经确定好了,这个就是所谓的词法作用域
在 js 中的词法作用域规则
1. 函数允许方位函数外的数据
2. 整个代码结构中只有函数可以限定作用域
3. 作用规则首先是提升规则分析
4. 就近原则如果当前作用规则有了名字,就不考虑外面的名字
在 js 中作用域分析方法
1. 先进行预解析,分析预解析过程 * 程序在执行过程, 会先将代码读取到内存中检查. 会将所有的声明在此时进行标记. 所谓的标记就是 让 js 解释器知道有这个名字, 后面在使用名字的时候, 不会出现未定义的错误. 这个标记过程就是提升. * 声明 1. 名字的声明, 标识符的声明( 变量名声明 ) * 名字的声明就是让我们的解释器知道有这个名字 * 名字没有任何数据与之对应 2. 函数的声明 * 函数声明包含两部分 * 函数声明与函数表达式有区别, 函数声明是单独写在一个结构中, 不存在任何语句, 逻辑判断等结构中 * 首先函数声明告诉解释器有这个名字存在. 该阶段与名字声明一样 * 告诉解释器, 这个名字对应的函数体是什么**(函数名和函数体绑定链接)** 2. 再进行代码执行过程
常见的简单作用域问题
例子 1:
var num = 123; function foo(){ console.log(num); } foo(); // 输出 123
分析
预解析
变量num变量名提升 函数foo函数名提升代码执行
num赋值123,函数内区域为独立区域,可以使用外部数据,但是现在变量名相同,覆盖外面的值 函数foo执行 函数区域中变量num变量名提升 输出num 为undefined num赋值456 输出num 为456
例子 2:
if(false){ var num = 123; } console.log(num); // 输出undefined
分析
预解析
变量名num提升执行代码
if判断为false,不进入 输出num,num定义未赋值,为undefined
例子 3:
var num = 123; function foo(){ var num = 456; function fn(){ console.log(num); // 输出456 }; fn(); } foo();
分析
预解析
变量名num和函数名foo声明提升,函数名foo和函数体链接执行代码
num = 123, 赋值 执行函数, 函数内部声明提升,变量名num和函数名fn 变量num=456, 执行函数fn 输出num, fn函数内部没有num,向上级寻找 num=456, 输出num
例子 4:
var num = 123; function foo1(){ var num = 456; function foo2(){ num = 789; function foo3(){ console.log(num); // 输出789 } foo3(); } foo2(); } foo1(); // 输出456 console.log(num); // 输出123
分析
预解析
变量名num和函数名foo1声明提升,函数名foo1和函数体绑定执行代码
num = 123, 赋值 执行函数foo1, 变量名num和函数名foo2声明提升, 函数名foo2和函数体绑定 num = 456, 赋值 执行函数foo2, num在foo2函数中没有, 访问上级foo1得到num, num = 789, 赋值函数名foo3声明提升并且绑定函数体 执行函数foo3, 输出num, foo3中没有num,访问上级,得到num = 789 输出num为789 跳出函数, 输出num为123
例子 5:
if ( ! 'a' in window ) { var a = 123; } console.log( a ); // undefined
分析
预解析
变量a声明提升执行代码
判断window中是否存在a,a存在 判断为false,不执行if中的代码 输出a,为undefined
复杂的作用域问题
例子 1
if ( true ) { function f1 () { console.log( 'true' ); } } else { function f1 () { console.log( 'false' ); } } f1();
分析
新版浏览器
预解析
无,函数f1被浏览器认为是函数表达式,不进行变量名提升执行代码
if判断进入true 执行函数表达式f1 输出结果为true旧版浏览器
预解析
函数f1变量声明提升,f1函数名和最后一个函数体连接在一起执行代码
if判断进入true 执行f1 输出false
例子 2
if ( false ) { function f1 () { console.log( 'true' ); } } else { function f1 () { console.log( 'false' ); } } f1();
分析
新版浏览器
预解析
无,f1为函数表达式,没有进行声明提升执行代码
if判断 执行f1 输出false旧版浏览器
预解析
函数名f1,声明提升,函数名和最后一个函数体链接在一起执行代码
if判断 执行f1 输出false
例子 3
var num = 123; function f1() { console.log( num ); } function f2() { var num = 456; f1(); } f2();
分析
预解析
声明提升,变量num,函数名f1,f2,函数名和函数体链接执行代码
num = 123 执行函数f2 变量num赋值456 执行函数f1 输出num,函数里面没有,向上寻找,上级为(0级作用域链),num=123,输出num为123
例子 4
var num = 123; function f1() { console.log( num ); } function f2() { num = 456; f1(num); } f2();
分析
预解析
变量名num,函数名f1,f2声明提升,函数名和函数体链接一起代码执行
num=123 执行函数f2 num=456,f2中没有num,向上级寻找得到num为123,将num = 123赋值,num = 456 执行f1, f1中没有num, 向上级寻找得到num为456 输出num,num=456,输出num456
来源:https://www.cnblogs.com/liu666/p/5747667.html