Javascript 作用域、作用域链和闭包

本文详细解析了JavaScript中的作用域概念,包括局部变量的访问限制,作用域链的形成,以及闭包如何使函数读取其他函数的内部变量。通过实例展示了闭包的应用,如计算月开销的函数,强调了实践对于深入理解的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

先上定义
  • 作用域: 官方解释:一段程序代码中所用到的变量并不总是可用的,而限定这个变量的可用性的代码范围就是改变量的作用域
  • 闭包: 闭包就是能够读取其他函数内部变量的函数

任何没有代码来支撑的定义和解释都是扯淡,务必静下心来看看下面的例子

作用域

举?一:

function outFun() {
	var num = 1  //  内部变量 num
 	console.log(num)  // 1
}
console.log(num)   // 通过运行上面的代码 控制台 打印结果  ReferenceError: num is not defined
outFun() 

上述简单的演示就可以出刊端倪,也如您所愿,之所有产生如上结果,就是因为变量 num 只存在于 count 函数内,被称之为局部变量,只有 count 内部可以访问

举?二:

function outFun() {
	var num = 1  // 变量 num 在函数 count 内部
 		function innerFun() {
 			console.log(num) // 1
 			 // ......  此处省略 n 多函数
		 }
		// ......  此处省略 n 多函数
	console.log(num) // 1
	console.log(innerFun())
}
outFun() 

运行上述代码,你会发现,内部函数 innerFun 中也可以正常输出 num 的值,这是因为 innerFun 在外部函数 outFun 内部

举?三:

function outFun() {
	var num = 1  // 变量 num 在函数 count 内部
 		function innerFun() {
 			var count = 999;
 			console.log(num)   // 1
 			console.log(count) // 999
 			// ......  此处省略 n 多函数
		 }
		 //  ......  此处省略 n 多函数
	console.log(num)   // 1
	console.log(innerFun())
	console.log(count)  // undefined
}
outFun() 

运行上述代码,你会发现,内部函数 innerFun 中也可以正常输出 num 的值,这是因为 innerFun 在外部函数 outFun 内部,但是 外部函数 outFun 无法访问 内部函数 innerFun 中的 count 变量。

以上三个简单的例子,很好的解释了最初的定义(记得巩固一下),当然每一个Function都有自己的作用域这个你得知道,不要问我为什么。

作用域链

提问

  1. 什么是作用域链?
  2. 作用域链是怎么形成的?

这里就不引用一些官方的解释了,太绕而且不易读,这里只谈谈自己的理解

  • 作用域链:函数的嵌套形成不同的层级的作用域,内层函数对外层函数中变量的引用形成作用域链

也就是说,作用域链的形成以及复杂程度和函数的嵌套有关

图解作用域链:

在这里插入图片描述

闭包

在讲解闭包之前先讲讲个人理解的闭包的模式:外层函数的局部变量被内层函数所引用,调用外层函数返回内层函数

举例:

function a() {
	var str = 'hello world'
	return function b() {
  		console.log(str)
	}
}
a()  // 返回 内层函数 b, 但是根据垃圾回收机制, 函数 a 中的局部变量 str 依然被函数 b 所使用,所以不会被系统进行回收,也就会一直占用内存

关于堆栈调用请狠狠的点击这里:https://mp.youkuaiyun.com/postedit/85038675
如此就形成了一个最简单的闭包

讲完了基础的定义,再来看看实际使用场景

编写一个计算月开销的函数,不用每天就进行计算,只有在需要的时候进行求值:

var cost = (function(){
  var args = [];
  return function(){
    if ( arguments.length === 0 ){
      var money = 0;
      for ( var i = 0, l = args.length; i < l; i++ ){
        money += args[ i ];
      }
      return money;
    }else{
      // 传参的时候
      Array.prototype.push.apply( args , arguments ); // 向数组中添加成员
    }
  }
})();
cost( 100 ); // 未真正求值
cost( 200 ); // 未真正求值
cost( 300 ); // 未真正求值
console.log( cost() ); // 求值并输出: 600

以上代码通过匿名函数的自调返回每部函数,内部函数始终保持对外层函数的引用

结语

以上是对作用域、作用域链、以及闭包的最简单且最直接的讲解,万变不离其中,更深入的理解和运用,需要去实践,可以参考面试题的分享 某上市公司的前端面试题

其它前端性能优化:

前端技术架构体系(没有链接的后续跟进):

其它相关

欢迎各位看官的批评和指正,共同学习和成长
希望该文章对您有帮助,你的 支持和鼓励会是我持续的动力

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值