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。


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

猜你喜欢

转载自blog.csdn.net/qq_43738157/article/details/84547184