IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> javaScript的作用域、闭包 -> 正文阅读

[JavaScript知识库]javaScript的作用域、闭包

前言

JavaScript 中的闭包是相当重要的概念,并且与作用域相关知识的指向密切相关。
那么,
JavaScript 中的作用域是什么?
闭包会在哪些场景中使用?

作用域

JavaScript 的作用域通俗来讲,就是指变量能够被访问到的范围,在 JavaScript 中作用域也分为好几种,ES5 之前只有全局作用域函数作用域两种。ES6 出现之后,又新增了块级作用域

全局作用域

在编程语言中,变量一般都会分为全局变量和局部变量两种。那么变量定义在函数外部,代码最前面的一般情况下都是全局变量。

在 JavaScript 中所有没有经过定义,而直接被赋值的变量默认就是一个全局变量。

全局变量是挂载在 window 对象下的变量,所以在网页中的任何位置你都可以使用并且访问到这个全局变量。

函数作用域

在 JavaScript 中,函数中定义的变量叫作函数变量,这个时候只能在函数内部才能访问到它,所以它的作用域也就是函数的内部,称为函数作用域。

同时,当这个函数被执行完之后,这个局部变量也相应会被销毁

块级作用域

ES6 中新增了块级作用域,最直接的表现就是新增的 let 关键词,使用 let 关键词定义的变量只能在块级作用域中被访问,有“暂时性死区”的特点,也就是说这个变量在定义之前是不能被使用的。

举个例子,其实就是在 JS 编码过程中 if 语句及 for 语句后面 {…} 这里面所包括的,就是块级作用域。

console.log(a) //a is not defined
if(true){
  let a = '123';
  console.log(a)// 123
}
console.log(a) //a is not defined

闭包

官方定义

闭包是指有权访问另外一个函数作用域中的变量的函数。

一个函数和对其周围状态的引用捆绑在一起(或者说函数被引用包围),这样的组合就是闭包(closure)。也就是说,闭包让你可以在一个内层函数中访问到其外层函数的作用域。

闭包的基本概念

通俗的说:闭包其实就是一个可以访问其他函数内部变量的函数。即一个定义在函数内部的函数,或者直接说闭包是个内嵌函数也可以。

因为通常情况下,函数内部变量是无法在外部访问的(即全局变量和局部变量的区别),因此使用闭包的作用,就具备实现了能在外部访问某个函数内部变量的功能,让这些内部变量的值始终可以保存在内存中。

function fun1() {
	var a = 1;
	return function(){
		console.log(a);
	};
}
var result = fun1();
result();  // 1

闭包产生的原因

作用域链的基本概念:
当访问一个变量时,代码解释器会首先在当前的作用域查找,如果没找到,就去父级作用域去查找,直到找到该变量或者不存在父级作用域中,这样的链路就是作用域链。

每一个子函数都会拷贝上级的作用域,形成一个作用域的链条

var a = 1;
function fun1() {
  var a = 2
  function fun2() {
    var a = 3;
    console.log(a);//3
  }
}

fun1 函数的作用域是它自己本身,并且有一个指向全局作用域(window)的引用,即自身 + window;fun2 函数的作用域是它本身,并且有一个指向fun1作用于的引用,而fun1又有一个指向全局作用域的引用,所以fun2的作用域是自身 + fun1 + window;而作用域是从最底层向上找,直到找到全局作用域 window 为止,如果全局还没有的话就会报错。

那么这就很形象地说明了什么是作用域链即当前函数一般都会存在上层函数的作用域的引用,那么他们就形成了一条作用域链

由此可见,闭包产生的本质就是:当前环境中存在指向父级作用域的引用。

如下代码,就产生了闭包:

function fun1() {
  var a = 2
  function fun2() {
    console.log(a);  //2
  }
  return fun2;
}
var result = fun1();
result();

那是不是只有返回函数才算是产生了闭包呢?其实也不是,回到闭包的本质,我们只需要让父级作用域的引用存在即可

var fun3;
function fun1() {
  var a = 2
  fun3 = function() {
    console.log(a);
  }
}
fun1();
fun3();

闭包的表现形式

  1. 返回一个函数。
  2. 在定时器、事件监听、Ajax 请求、Web Workers 或者任何异步中,只要使用了回调函数,实际上就是在使用闭包。这些都是平常开发中用到的形式。
// 定时器
setTimeout(function handler(){
  console.log('1');
}1000);
// 事件监听
$('#app').click(function(){
  console.log('Event Listener');
});
  1. 作为函数参数传递的形式。
var a = 1;
function foo(){
  var a = 2;
  function baz(){
    console.log(a);
  }
  bar(baz);
}
function bar(fn){
  // 这就是闭包
  fn();
}
foo();  // 输出2,而不是1
  1. IIFE(立即执行函数),创建了闭包,保存了全局作用域(window)和当前函数的作用域,因此可以输出全局的变量。
var a = 2;
(function IIFE(){
  console.log(a);  // 输出2
})();

利用闭包解决循环输出问题

经典的例子:

for(var i = 1; i <= 5; i ++){
  setTimeout(function() {
    console.log(i)
  }, 0)
}

相信大家都知道最后会打印 5 个 6,而不是0、1、2、3、4、5。
简单分析原因:

setTimeout 为宏任务,由于 JS 中单线程 eventLoop 机制,在主线程同步任务执行完后才去执行宏任务,因此循环结束后 setTimeout 中的回调才依次执行。

因为 setTimeout 函数也是一种闭包,往上找它的父级作用域链就是 window,变量 i 为 window 上的全局变量,开始执行 setTimeout 之前变量 i 已经就是 6 了,因此最后输出的连续就都是 6。

利用 IIFE

可以利用 IIFE(立即执行函数),当每次 for 循环时,把此时的变量 i 传递到定时器中,然后执行,改造之后的代码如下。

for(var i = 1;i <= 5;i++){
  (function(j){
    setTimeout(function timer(){
      console.log(j)
    }, 0)
  })(i)
}

使用 ES6 中的 let

for(let i = 1; i <= 5; i++){
  setTimeout(function() {
    console.log(i);
  },0)
}

定时器传入第三个参数

setTimeout 作为经常使用的定时器,它是存在第三个参数的。
附加参数,一旦定时器到期,它们会作为参数传递给。

for(var i=1;i<=5;i++){
  setTimeout(function(j) {
    console.log(j)
  }, 0, i)
}
  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2022-04-28 11:44:26  更:2022-04-28 11:45:57 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 1:00:41-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码