js函数高级:04、详解执行上下文与执行上下文栈(变量提升与函数提升、执行上下文、执行上下文栈)及相关面试题

javascript 的变量提升与函数提升、执行上下文、执行上下文栈及相关面试题解:

Ⅰ、变量提升与函数提升:

其一、代码为:

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>01_变量提升与函数提升</title>
</head>
<body>
	<!--
	1、变量声明提升:
		* 通过 var 定义(声明)的变量,在定义语句之前就可以访问到;
		*	值为:undefined

	2、函数声明提升:
		*	通过 function 声明的函数,在之前就可以直接调用
		*	值为:函数定义(对象)

	注意:无论是变量声明提升还是函数声明提升,都是一个现象结果(核心是:如何产生或导致了该现象结果);

	3、问题:变量提升和函数提升是如何产生的?
	-->
	
	<script type="text/javascript">
	console.log("----------------")// 此处可以作为 window 打印定位的锚点;

	/* 
	面试题:输出 undefined
	*/
	var a = 3
	function fn() {
		console.log(a)// undefined,原因:fn 函数内部有 a 变量的声明,因此不调用函数外声明的 var a = 3,而 fn 函数内的 var a = 4 语句只是声明了但没赋值,因此输出为 undefined;
		var a = 4
	} 
	fn()


	console.log(b)// undefined,原因:变量提升;
	fn2()// 'fn2()',可调用,原因:函数提升(使用声明方式来声明函数);
	fn3()// Uncaught TypeError: fn3 is not a function,不能调用,原因:变量提升(注意此时遵循的是变量提升而不是函数提升,因为此时不是使用声明的方式声明函数);

	var b = 3
	function fn2() {
		console.log('fn2()')
	}

	var fn3 = function() {
		console.log('fn3()')
	}
		
	</script>
</body>
</html>

其二、结果为:

// 一进入页面后的控制台:

Ⅱ、执行上下文:

其一、代码为:

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>02_执行上下文</title>
</head>
<body>
	<!--  
	1、代码分类(根据位置来分类)
		*	全局代码
		*	函数(局部)代码


	2、全局执行上下文:
		*	在执行全局代码前将 window 确定为全局执行上下文
		*	对全局数据进行预处理
			*	var 定义的全局变量 ==> undefined,添加为 window 的属性;
			* function 声明的全局函数 ==> 赋值(fun,即:函数对象),添加为 window 的方法;
			*	this ==> 赋值(window 对象)
		* 开始执行全局代码


	3、函数执行上下文:
		*	在调用函数,准备执行函数体之前,创建对应的函数执行上下文对象(虚拟的,存在于栈中);
		*	对局部数据进行预处理
			*	形参变量 ==> 赋值(实参) ==> 添加为执行上下文的属性
			*	arguments ==> 赋值(实参列表),添加为执行上下文的属性
			*	var 定义的局部变量 ==> undefined,添加为执行上下文的属性
			*	function 声明的函数 ==> 赋值(fun,即:函数对象),添加为执行上下文的方法
			*	this ==> 赋值(调用函数的对象)
		*	开始执行函数体代码

	-->

	<script type="text/javascript">

	// 全局执行上下文:
	c = 3// 不能在执行该语句之前添加为 window 的属性:因为不是通过 var 来定义的全局变量(注意:只有通过 var 定义的全局变量才能进行预处理,才能添加到 window 对象上);
			 // 而非 var 定义的全局变量并没有报错(因为语法允许),但只有在执行该 c = 3 语句后,才能添加到 window 对象上;
	console.log(a1)// undefined,本质是:window.a1
	console.log(a2)// ƒ a2() { console.log('a2()') },本质是:window.a2
	console.log(a2())// a2(),undefined,本质是:window.a2()
									 // 输出 a2() 的原因:调用了 a2 函数、输出 undefined 的原因:该 a2 函数没有返回值,因此输出为 undefined;
	console.log(this)// window 对象

	var a1 = 3
	function a2() {
		console.log('a2()')
	}
	console.log('a1')// a1
	console.log('----------------------------------------------------')




	// 函数执行上下文:
	function fn(a1) {
		console.log(a1)// 2
		console.log(a2)// undefined
		a3()// 'a3()'
		console.log(this)// Window 对象
		console.log(arguments)// (2,3)(即:伪数组,Arguments 对象)

		var a2 = 3
		function a3() {
			console.log('a3()')
		}
	}

	fn(2,3)
	</script>
</body>
</html>

其二、结果为:

// 一进入页面后的控制台:

Ⅲ、执行上下文栈:

其一、代码为:

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>03_执行上下文栈1</title>
</head>
<body>
	<!--  
	1、在全局代码执行前,JS 引擎就会创建一个栈来存储管理所有的执行上下文对象;

	2、在全局执行上下文(window)确定后,将其添加到栈中(压栈);

	3、在函数执行上下文创建后,将其添加到栈中(压栈);

	4、在当前函数执行完后,将栈顶的对象移除(出栈);

	5、当所有的代码执行完后,栈中只剩下 window;

	6(*)、执行上下文的个数的确定:函数调用的个数 + 全局执行上下文(即:N + 1)
	-->
	<script type="text/javascript">

  // 代码产生过三个执行上下文对象:Window、bar(10) 函数调用、foo(x + b) 函数调用(注意:只有函数被调用才会产生函数执行上下文对象,函数仅声明并不会产生函数执行上下文对象);
	var a = 10
	var bar = function(x) {
		var b = 5
		foo(x + b)// 此时能成功执行的原因:不能遵循变量提升原则,因为此时的 foo(x + b) 函数执行是在 foo 函数完全声明后,因此此时并不会报错;
	}
	var foo = function(y) {
		var c = 5
		console.log(a + c + y)// 30
	}
	bar(10)
		
	</script>
</body>
</html>

其二、结果为:

// 一进入页面后的控制台:

其三、代码为:

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>04_执行上下文栈2</title>
</head>
<body>
	<!--
	1、依次输出什么?

		global begin: undefined

		foo() begin: 1
		foo() begin: 2
		foo() begin: 3
		foo() end: 3
		foo() end: 2
		foo() end: 1

		global end: 1

	2、整个过程中产生了几个执行上下文?
		N + 1 ==> 4 + 1 ==> 5
		
	-->
	<script type="text/javascript">
	
	console.log('global begin: ' + i)
	var i = 1
	foo(1)
	function foo(i) {
		if(i == 4) {
			return
		}
		console.log('foo() begin:' + i)
		foo(i + 1)// 递归调用:在函数内部调用自己
		console.log('foo() end:' + i)
	}
	console.log('global end: ' + i)
		
	</script>
</body>
</html>

其四、结果为:

// 一进入页面后的控制台:

其五、执行上下文栈的流程分析:

// 图一是案例的流程分析,图二是执行上下文逻辑分析;

Ⅳ、面试题:

其一、代码为:

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>05_面试题</title>
</head>
<body>
	<script type="text/javascript">

  /*  
	 测试题1:核心问题:变量提升与函数提升,谁先提升?
	*/
	// 答:先执行变量提升,再执行函数提升;
	function a() {}
	var a 
	console.log(typeof a)// 'function'(先执行变量提升,再执行函数提升,因此输出结果为:function,反过来则输出 undefined)


	

  /*  
	 测试题2:
	*/
	if(!(b in window)) {// 判断在 window 对象中,是否存在 b 属性
		var b = 1
	}
	console.log(b)// undefined(说明:b 存在变量提升,b in window 为 true,因此输出结果为 undefined)(注意:此时是 if(){} 语句,而非函数内部)
								// 只能存在的两种结果:undefined(说明 var b = 1 没有执行过)、1 (说明 var b = 1 执行过)




  /*  
	 测试题3:
	*/
	var c = 1
	function c(c) {
		console.log(c)
	}
	console.log(this)
	c(2)// Uncaught TypeError: c is not a function
			// 报错点:先执行变量提升,再执行函数提升,因此在函数提升过后就在 window 中存在了 c 函数,因此再给 c 变量赋值的时候就报错了( c = 1 就会报错),因此还没执行 c(2) 语句就报错了;
			// 核心点:报错点没问题,但是在调用 c(2) 的过程中,c 就不再是一个函数了,因为已经有 c 的变量声明;
		
	</script>
</body>
</html>

其二、结果为:

// 一进入页面后的控制台:

Ⅴ、小结:

其一、哪里有不对或不合适的地方,还请大佬们多多指点和交流!
其二、若有转发或引用本文章内容,请注明本博客地址(直接点击下面 url 跳转) https://blog.csdn.net/weixin_43405300,创作不易,且行且珍惜!
其三、有兴趣的话,可以多多关注这个专栏(Vue(Vue2+Vue3)面试必备专栏)(直接点击下面 url 跳转):https://blog.csdn.net/weixin_43405300/category_11525646.html?spm=1001.2014.3001.5482
其四、再有兴趣的话,也可以多多关注这个专栏(Java)(直接点击下面 url 跳转):https://blog.csdn.net/weixin_43405300/category_12654744.html?spm=1001.2014.3001.5482

相关推荐
爱学习的程序媛1 小时前
《JavaScript权威指南》核心知识点梳理
开发语言·前端·javascript·ecmascript
乐观主义现代人2 小时前
go 面试
java·前端·javascript
1***Q7842 小时前
前端在移动端中的离线功能
前端
星环处相逢2 小时前
Nginx 优化与防盗链及扩展配置指南
服务器·前端·nginx
2501_941886862 小时前
多语言微服务架构下的微服务熔断与限流优化实践
javascript
tsumikistep2 小时前
【前后端】Vue 脚手架与前端工程结构入门指南
前端·javascript·vue.js
在繁华处2 小时前
JAVA实战:文件管理系统1.0
java·开发语言·前端
GISer_Jing2 小时前
SSE Conf大会分享支付宝xUI引擎:AI时代的多模态交互革命
前端·人工智能·交互
Aerelin2 小时前
爬虫playwright中的资源监听
前端·爬虫·js·playwright