JS作用域:全局作用域,函数作用域,块级作用域

JS作用域:全局作用域,函数作用域,块级作用域

  • 背景
  • 作用域
    • 全局作用域
    • 函数作用域
    • 块级作用域
      • 通过调用栈分析块级作用域
      • 开发者工具查看作用域
      • 选项卡示例

背景

由于 JavaScript 存在变量提升这种特性,从而导致很多与直觉不符的代码,这也是 JavaScript 的一个重要设计缺陷,这种设计缺陷带来的问题可以去看看JS变量和函数提升。

所以 ES6 通过引入块级作用域并配合 letconst 关键字来避开了这种设计缺陷,但是由于 JavaScript 需要向下兼容,所以变量提升在相当长一段时间内还会继续存在。

作用域

作用域是指在程序中定义变量的区域,该位置决定了变量的生命周期。即,作用域是变量和函数的可访问范围,控制着变量和函数的可见性和生命周期。

ES6(2015年6月) 之前,ES 的作用域只有两种:全局作用域函数作用域。相较而言,其他语言则都普遍支持块级作用域

全局作用域

全局作用域中的对象在代码中的任何地方都能访问,其生命周期伴随着页面的生命周期。

函数作用域

函数作用域就是在函数内部定义的变量或函数,并且定义的变量或函数只能在函数内部被访问,函数执行结束后,函数内部定义的变量就会被销毁。

块级作用域

ES6 中给 JavaScript 新增了块级作用域

  • 块级作用域由{}包括,if语句和for语句里面的{}都属于块级作用域
  • var定义的变量没有块级作用域概念,可以跨块级作用域访问
  • letconst定义的变量只能在块级作用域里访问

下面几段示例代码可以帮助你对块级作用域的理解:

{
	var a = 1
	let b = 2
	const c = 3
}
console.log(a) // 1
console.log(b) // 报错(let和const只能在块级作用域中访问)
console.log(c) // 报错
for(var a = 0; a < 3; a++) {
  var d = 5
}
console.log(a) // 3
console.log(d) // 5

for(let a = 0; a < 3; a++) {
  var d = 5
}
console.log(a) // 报错(for语句属于块级作用域)
console.log(d) // 5
if(true) {
  var a = 5
}
console.log(a) // 5

if(true) {
  let a = 5
}
console.log(a) // 报错(if语句属于块级作用域)

通过调用栈分析块级作用域

不了解调用栈的可以先去看JS调用栈

function foo() {
 var a = 1
 let b = 2
 {
   let b = 3
   var c = 4
   let d = 5
   console.log(a)
   console.log(b)
 }
 console.log(b)
 console.log(c)
 console.log(d)
}
foo()
  1. 第一步编译并创建执行上下文。函数内部通过 var 声明的变量在编译阶段全都被存到变量环境里
    在这里插入图片描述

  2. 第二步继续执行代码。执行到函数内部代码块,在块级作用域之前,变量环境中的 a 已经被设置成了 1,词法环境中的 b 已经被设置成了 2
    在这里插入图片描述

  3. 进入函数内的块级作用域,块级作用域中通过 let 声明的变量会被存放在词法环境一个单独的区域中,这个区域中的变量并不影响块级作用域块外面的变量,比如它们都有一个变量 b其实在词法环境中维护了一个小型的栈结构,栈底时函数最外层的变量,进入一个块级作用域后,就会把该作用域内的变量压入栈中,当该作用域执行完成后就从栈中弹出。当然,这里的变量是指通过 letconst 声明的变量。
    在这里插入图片描述

  4. 当执行到块级作用域中的 console.log(a) 这行代码时,需要在词法环境和变量环境中查找 a 的值,具体查找方向是:沿着词法环境的栈顶向下查询,如果有直接返回给 JavaScript 引擎,如果都没有就去变量环境中查找。

  5. 块级作用域执行完后返回内容,弹出栈中,执行结果为
    在这里插入图片描述
    在这里插入图片描述

所以,块级作用域是通过词法环境的栈结构来实现的,而变量提升是通过变量环境来实现的,通过两者的结合,JavaScript 引擎也就同时支持了变量提升和块级作用域了。

开发者工具查看作用域

var a = 'hello'
let b = 18
const c = 'female'
{
  var aa = 'hi'
  let bb = 188
  const cc = 'male'
  debugger
}
function foo() {
  var aaa = 'go'
  let bbb = 10
  const ccc = 'man'
  {
    var aaaa = 'ok'
    let bbbb = 8
    const dddd = 'girl'
    debugger
  }
  debugger
}
foo()

打开Chrome开发者工具查看这段代断点处作用域下变量值

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

选项卡示例

<style>
  button.active{
    color: red;
  }
  p{
    display: none;
  }
  p.active{
    display: block;
    background-color: red;
  }
</style>

<body>
  <button>选项一</button>
  <button>选项二</button>
  <button>选项三</button>

  <p>内容一</p>
  <p>内容二</p>
  <p>内容三</p>
</body>
// 用var
<script>
  let buttons = document.querySelectorAll('button')
  let ps = document.querySelectorAll('p')

  for(var i = 0; i < buttons.length; i++) {
    buttons[i].index = i
    buttons[i].onclick = function() {
      for(var j = 0; j < buttons.length; j++) {
        buttons[j].className = ''
        ps[j].className = ''
      }
      this.className = 'active'
      ps[this.index].className = 'active'
    }
  }
</script>
</body>
// 使用let块级作用域
let buttons = document.querySelectorAll('button')
let ps = document.querySelectorAll('p')

for(let i = 0; i < buttons.length; i++) {
  buttons[i].onclick = function() {
    for(var j = 0; j < buttons.length; j++) {
      buttons[j].className = ''
      ps[j].className = ''
    }
    this.className = 'active'
    ps[i].className = 'active' // i的for循环每一次都会生成一个块级作用域所以每个i都在指定的作用域中工作
  }
}

总结:选项卡实例中,使用var没有块级作用域所以for循环结束,i就变成了最后的值,所以必须要将索引值赋值给每一个元素,然后点击的时候根据索引去判断显影性。
使用let创造了块级作用域,每次循环都会创造一个块级作用域的i,所以可以直接使用ps[i]去对对应的元素设置类名。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/282560.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

详解数组的轮转

&#x1d649;&#x1d65e;&#x1d658;&#x1d65a;!!&#x1f44f;&#x1f3fb;‧✧̣̥̇‧✦&#x1f44f;&#x1f3fb;‧✧̣̥̇‧✦ &#x1f44f;&#x1f3fb;‧✧̣̥̇:Solitary-walk ⸝⋆ ━━━┓ - 个性标签 - &#xff1a;来于“云”的“羽球人”。…

Git 分布式版本控制系统(序章1)

第一章 Git 分布式版本控制系统 为什么学Git? 某些企业面试需要掌握Git&#xff0c;同时&#xff0c;也方便管理自己的Qt项目。 一、Git 客户端下载&#xff08;Windows&#xff09; 下载地址 https://gitee.com/all-about-git#git-%E5%A4%A7%E5%85%A8 二、Git 的特点 分支…

vue3引入百度地图(两种方法)

首先要有百度开放平台并进行注册&#xff0c;不懂看这里 ### 第一种方法 地图引入流程 安装vue-baidu-map-3x插件 参考官网地址&#xff1a;快速上手 | vue-baidu-map-3x npm install vue-baidu-map-3x --save 在public/index.html文件中引入 <!-- 百度地图 --> &…

微软开源,全平台通用:Shell 自动补全工具 | 开源日报 No.132

microsoft/inshellisense Stars: 7.6k License: MIT inshellisense 是一个为 Shell 提供 IDE 风格自动补全的工具。它是一个终端本地运行时自动完成&#xff0c;支持 600 多个命令行工具&#xff0c;并且可以在 Windows、Linux 和 macOS 上使用。主要功能包括安装后可通过运行…

HTML教程(1)——概述和第一个网页

一、什么是HTML HTML 是用来描述网页的一种语言。 HTML 指的是超文本标记语言 (Hyper Text Markup Language)HTML 不是一种编程语言&#xff0c;而是一种标记语言 (markup language)标记语言是一套标记标签 (markup tag)HTML 使用标记标签来描述网页 二、什么是HTML 标签 H…

设计模式:工厂方法模式(讲故事图文易懂)

目录 简单工厂工厂方法模式 简单工厂 定义&#xff1a;简单工厂由一个工厂根据参数类型决定创建哪种产品的实例。 简单工厂不包含在23种设计模式之内&#xff08;简单工厂不满足开闭原则&#xff0c;后面会详细讲&#xff09; 举例&#xff1a;张三去4S店买了车&#xff0c;显…

城市生态数据大屏,PSD设计稿

现分享生态系统可视化大数据大屏的 Photoshop 源文件&#xff0c;下载即用&#xff01;以下为截图示意。 若需 更多行业 相关的大屏&#xff0c;请移步小7的另一篇文章&#xff1a;200套精选数据可视化大屏&#xff0c;大屏PSD设计&#xff08;各行业大屏UI&#xff09;https:…

DevExpress 皮肤改变触发后触发的事件,用来保存皮肤配置

代码&#xff1a; private UserLookAndFeel userLookAndFeel; public MainGeneral() {InitializeComponent();// 创建 UserLookAndFeel 实例userLookAndFeel new UserLookAndFeel(this);// 订阅 StyleChanged 事件userLookAndFeel.StyleChanged UserLookAndFeel_StyleChange…

UDP套接字搭建简易服务器与客户端

使用UDP套接字搭建 文章目录 使用UDP套接字搭建前言一、基本结构二、使用步骤1.服务器端2.客户端 三、效果展示总结 前言 这次较上个版本《Python 网络编程之搭建简易服务器和客户端》https://only-me.blog.csdn.net/article/details/135251171增加了&#xff1a; UDP协议来进…

1.PHP简单入门

1.PHP代码执行方式 PHP是在服务器端执行&#xff0c;然后返回给用户结果。 如果直接使用浏览器打开&#xff0c;就会解析为文本。 意思是说&#xff0c;浏览器通过 http请求&#xff0c;才能够执行php页面。 2.PHP代码框架 开启本机服务器&#xff08;下载软件略&#xff09…

数据结构: 位图

位图 概念 用一个bit为来标识数据在不在 功能 节省空间快速查找一个数在不在一个集合中排序 去重求两个集合的交集,并集操作系统中的磁盘标记 简单实现 1.设计思想:一个bit位标识一个数据, 使用char(8bit位)集合来模拟 2.预备工作:a.计算这个数在第几个char b.是这个ch…

全球日光地图分布地图数据

日光地图分布地图数据 Daylight 是全球开放地图数据的完整分发版&#xff0c;可在社区和专业地图制作者的支持下免费获取。我们将 OpenStreetMap 等项目的全球贡献者的工作与日光制图合作伙伴的质量和一致性检查结合起来&#xff0c;创建免费、稳定且易于使用的街道比例全球地…

【K8S 部署】基于kubeadm搭建Kurbernetes集群

目录 一、基本架构 二、环境准备: 三、安装部署 1、所有节点安装docker 2、、所有节点安装kubeadm&#xff0c;kubelet和kubectl 3、配置网络--flannel 4、测试 pod 资源创建 四、安装部署与k8s集群对接的Harbor仓库 五、Dashboard安装部署&#xff1a; 一、基本架构…

基于单片机的语音识别自动避障小车(论文+源码)

1.系统设计 此次基于单片机的语音识别自动避障小车&#xff0c;以STC89C52单片机作为系统的主控制器&#xff0c;利用超声波模块来实现小车与障碍物距离的测量并通过LCD液晶显示&#xff0c;当距离低于阈值时会通过WT588语音模块进行报警提示&#xff0c;并且小车会后退来躲避…

微信小程序-父子页面传值

父子页面传值 父页面向子页面传值 方法一&#xff1a; 父页面&#xff1a; 1. /page/xxx/xxx?id1子页面&#xff1a; onLoad:function(option){ }方法二 <bindtap“func” data-xxx””> 子页面向父页面传值 定义父子页面 父页面&#xff1a;hotspot 子页面&a…

uni-app App.vue生命周期全局样式全局存储globalData

锋哥原创的uni-app视频教程&#xff1a; 2023版uniapp从入门到上天视频教程(Java后端无废话版)&#xff0c;火爆更新中..._哔哩哔哩_bilibili2023版uniapp从入门到上天视频教程(Java后端无废话版)&#xff0c;火爆更新中...共计23条视频&#xff0c;包括&#xff1a;第1讲 uni…

程序员必备的数据处理神器-瑞士军刀cyberchef

本文将介绍一款强大的工具&#xff0c;囊括了网络世界范围内绝大数据的编解码技术&#xff0c;加解密技术&#xff0c;数格式转换技术&#xff0c;并提供了编码和解码&#xff0c;加解密以及数据转换的方法方法。对于程序员&#xff0c;这一一款不可多得的神器&#xff0c;在也…

<Icon-ResizER>support

If you get any questions in using app, email me caohechunhotmail.com.

OPenGL GLSL

shji 数据类型 整型&#xff08;有符号/无符号&#xff09; 浮点数&#xff08;单精度&#xff09; 布尔值 向量类型/矩阵类型 bool bDone false int value 1; unint vale 21u float value 2.1 向量/分量类型 vec2,vec3,vec4 2分量 3 分量 4 分量复电向量 i…

深入了解小红书笔记详情API:为内容创新提供动力

一、小红书笔记详情API简介 小红书笔记详情API是一种允许开发者访问小红书平台上的笔记详细数据的接口。通过这个API&#xff0c;我们可以获取笔记的标题、内容、标签、点赞数、评论数等详细信息。这些数据对于内容创作者和品牌来说至关重要&#xff0c;可以帮助他们了解用户喜…