您的位置:首页 > Web前端 > JavaScript

JavaScript踩坑笔记07---作用域链、动态作用域、静态作用域、词法作用域

2018-11-26 15:52 155 查看

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。

个人学习总结,欢迎批评指正

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: