JavaScript踩坑笔记07---作用域链、动态作用域、静态作用域、词法作用域
JavaScript踩坑笔记07---作用域链、动态作用域、静态作用域、词法作用域
作用域链:
函数在定义时,不光确定了它内部的作用域,还确定了它外部的作用域,也就是作用域链。
举例说明。
// 全局变量num,boo var num = 1; var boo; function fn1() { function fn2() { function fn3() { // 依次从父级作用域找同名自由变量 console.log(num); // 1 // 直到全局作用域下也没找到该变量,证明该变量未声明,程序报错 console.log(str); // ReferenceError: str is not defined // 在全局作用域下找到变量boo,虽然已声明,但是并没有初始化,所以未定义 console.log(boo); // undefined } fn3(); } fn2(); } fn1();
在上述例子中,我定义了三个函数,并且依次嵌套。在函数fn3中并没有变量num,那么就只能找来自父作用域的同名自由变量,父作用域也没找到,再向上一级父作用域找同名的自由变量,最终找到变量num,如果最终没有找到该变量,那就证明该变量未声明,或未定义。这就是作用域链。
所以说找一个变量,只需要向其父作用域逐级向上找,就可以了吗?
JavaScript的作用域可没这么简单,要分清函数被调用时的作用域和函数定义时的作用域。下面动态作用域和静态作用域会说明。
动态作用域:
动态作用域指的是,在调用某个变量时,会从当前作用域逐级向上查找。
如果在当前作用域找到,就调用该变量,如果没找到,就继续向父级作用域查找,以此类推。
如果一直查找到最外层的全局作用域,都没有找到该变量,那么就表明没有该变量。
举例说明。
// 父级作用域变量num1 var num1 = 1; function fn() { // 当前作用域变量num2 var num2 = 2; // 在当前作用域没有找到变量num1,向父级作用域查找,在父级作用域找到变量num1,直接调用 console.log(num1); // 1 // 在当前作用域找到变量num2,直接调用 console.log(num2); // 2 // 在当前作用域没有找到变量num3,向父级作用域查找,在父级全局作用域也没找到变量num3,证明该变量未定义 console.log(num3); // ReferenceError: num3 is not defined } fn();
静态作用域、词法作用域:
静态作用域,又叫作词法作用域,函数在定义的时候,就已经确定了函数体内部自由变量的作用域。
JavaScript采用的是静态作用域。
举例说明。
// 全局变量num var num = "1"; function show() { function fn1() { console.log(num); } function fn2() { // 局部变量num var num = 2; fn1(); } fn2(); } show(); // 1
当执行函数fn时,会首先在函数show内部查找变量num,如果找到,则直接调用,如果没找到,就到函数show定义的作用域下查找,如果找到,则直接调用,如果没找到,则会逐级向上查找。
动态作用域与静态作用域的区别:
动态作用域的查找规则是程序执行时的函数调用顺序。
静态作用域的查找规则是距离当前作用域(声明的位置)最近的外层作用域中的同名变量。
《JavaScript权威指南》经典例子:
以下例子为《JavaScript权威指南》中经典的一个例子,基本网上的每个大佬都会提及。
例一:
var scope = "global scope"; function checkScope() { var scope = "local scope"; function fn() { return scope; } return fn(); } checkScope(); // local scope
分析:
在函数checkScope中定义了函数fn,并将函数fn的返回值当作函数checkScope的返回值返回。
首先在函数fn的内部作用域中找变量scope,没找到变量,所以在函数fn当前所在的作用域下找变量scope,找到变量,直接返回,所以返回的结果是local scope。
例二:
var scope = "global scope"; function checkScope() { var scope = "local scope"; function fn() { return scope; } return fn; } checkScope()(); // local scope
分析:
在函数checkScope中调用函数fn,函数fn同作用域下定义了变量scope,所以输出的是local scope。
在函数checkScope中定义了函数fn,并将函数fn当作函数checkScope的返回值返回,此时函数checkScope返回的是一个函数对象,不管这个返回的函数在哪里执行,当他定义时,他的作用域就已经确定了。
所以首先在函数fn的内部作用域中找变量scope,没找到变量,所以在函数fn当前所在的作用域下找变量scope,找到变量,直接返回,所以返回的结果还是local scope。
个人学习总结,欢迎批评指正
- Javascript高级编程学习笔记(10)—— 作用域、作用域链
- JavaScript学习笔记之作用域链
- JavaScript高级内容笔记:原型链、继承、执行上下文、作用域链、闭包
- JavaScript中作用域和作用域链的简单理解(变量提升)
- 深入理解javascript作用域系列第二篇——词法作用域和动态作用域
- 深入作用域之静态作用域与动态作用域
- JavaScript作用域、上下文、执行期上下文、作用域链、闭包
- JavaScript中作用域和作用域链的简单理解(变量提升)
- javascript 之作用域链-07
- JavaScript静态作用域和动态作用域
- javascript 之作用域链-07
- JavaScript的作用域,作用域链,变量
- 词法作用域与动态作用域的区别
- JavaScript笔记:函数作用域和块作用域
- JavaScript高级内容笔记:原型链、继承、执行上下文、作用域链、闭包
- 你不知道的JavaScript学习笔记1——作用域
- Javascript之作用域链
- JavaScript作用域学习笔记
- JavaScript笔记(4)作用域与作用域链
- JavaScript的作用域和块级作用域概念理解