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

先上定义

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

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

作用域

举?一:

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. 作用域链是怎么形成的?

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

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

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

图解作用域链:

Javascript 作用域、作用域链和闭包_第1张图片

闭包

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

举例:

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

关于堆栈调用请狠狠的点击这里:https://mp.csdn.net/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

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

结语

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

其它前端性能优化:

  • 图片优化——质量与性能的博弈
  • 浏览器缓存机制介绍与缓存策略剖析
  • webpack 性能调优与 Gzip 原理
  • 本地存储——从 Cookie 到 Web Storage、IndexDB
  • CDN 的缓存与回源机制解析
  • 服务端渲染的探索与实践
  • 解锁浏览器背后的运行机制
  • DOM 优化原理与基本实践
  • Event Loop 与异步更新策略
  • 回流(Reflow)与重绘(Repaint)
  • Lazy-Load
  • 事件的节流(throttle)与防抖(debounce
  • 前端学习资料下载
  • 技术体系分类

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

  • 调用堆栈
  • 作用域闭包
  • this全面解析
  • 深浅拷贝的原理
  • 原型prototype
  • 事件机制、
  • Event Loop
  • Promise机制、
  • async / await原理、
  • 防抖/节流原理
  • 模块化详解、
  • es6重难点、
  • 浏览器熏染原理、
  • webpack配置(原理)
  • 前端监控、
  • 跨域和安全、
  • 性能优化(参见上面性能优化相关)
  • VirtualDom原理、
  • Diff算法、
  • 数据的双向绑定
  • [TCP协议(三次握手、四次挥手)](https://blog.csdn.net/woleigequshawanyier/article/details/85223642
  • DNS域名解析

其它相关

  • 前端学习资料下载
  • 技术体系分类
  • react-native 实战项目学习
  • react-naitve 采坑笔记

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

你可能感兴趣的:(前端技术架构)