作用域与作用域链

作用域与作用域链

一、什么是作用域

作用域就是一个独立的代码区域,域内的变量不会暴露到外部,外部无法访问,也就是说具有隔离性。

function outFun() {
  var inVariable = "内层变量2";
}
outFun();
//  inVariable 的作用域仅在函数outFun内,外部无法访问
console.log(inVariable); // 结果 Uncaught ReferenceError: inVariable is not defined

JavaScript 使用词法作用域,也就说定义时就已经决定了作用域范围

JavaScript uses lexical scoping. This means that functions are executed using the variable scope that was in effect when they were defined, not the variable scope that is in effect when they are invoked.

JavaScript 使用词法作用域。 这意味着函数是使用定义时有效的变量范围来执行的,而不是调用它们时有效的变量范围。

二、作用域类型及效果

js 具有以下 3 类作用域

  • 全局作用域
  • 函数作用域
  • 块级作用域(ES6 之后才有的)

全局作用域

全局作用域就表示可以在代码任何地方访问到,以下几种情况均会产生全局作用域

  • 最外层函数
  • 最外层函数外面定义的变量
  • 未定义直接赋值的变量
  • 所有 windowns 对象的属性

最外层函数 和 最外层函数外面定义的变量

//最外层变量
var outVariable = "out variable";

//最外层函数
function outFun() {
  //内层变量
  var inVariable = "inner variable";

  //内层函数
  function innerFun() {
    console.log(inVariable);
  }
  innerFun();
}

// 最外层函数外的变量,作用域是全局,可以直接访问
console.log(outVariable); // 结果 out variable

// 最外层函数作用域是全局,可以直接访问
outFun(); // 结果 inner variable

// 局部变量,作用域仅在 outFun 函数内部,外部不可以访问
console.log(inVariable); //inVariable is not defined

// 内部函数, 作用域仅在 outFun 函数内部,外部不可以访问
innerFun(); //innerFun is not defined

未定义直接赋值的变量

function outFun() {
  undefVariable = "undefined variable";
}

outFun();
// 未定义直接赋值的变量,作用域是全局,可以直接访问
console.log(undefVariable); // 结果 undefined variable

所有 windowns 对象的属性

例如 window.name、window.location、window.top 等等,更多 windowns 属性见 MDN Window

函数作用域

在函数内部声明的变量,作用域是该函数内

作用域分层:内层作用域,可以访问外层作用域的变量,外层作用域不可以访问内层作用域

function foo(a) {
  var b = a * 2;
  function bar(c) {
    console.log(a, b, c);
  }
  bar(b * 3);
}
foo(2); // 结果 2 4 12

在这里插入图片描述

如上例子,共有 3 层作用域

  • 1 绿色部分是全局作用域(最外层函数产生全局作用域),该作用域拥有一个函数 foo
  • 2 黄色部分作用域是 foo 函数内部,该作用域拥有一个自定义的变量 b , 一个外部传入的变量 a , 一个函数 bar
  • 3 蓝色部分作用域是 bar 函数内部,该作用域有一个外部传入的变量 c

块语句(大括号“{}”中间的语句)不会创建新的作用域, 比如 if 语句、swtich 语句、for 循环语句、while 循环语句

// if 语句不会创建作用域,
if (true) {
  var a = 12; // a 属于最外层函数外定义的变量,所以在全局作用域中
}

块级作用域

ES6 之后,js 支持块级作用域,块级作用域内部的变量只能在指定块内部访问

如何产生块级作用域

  • 使用 let 声明变量
  • 使用 const 声明变量

块级作用域范围

  • 一个函数内部
  • 一个代码块(即一对大括号“{}”)内部

let/const 声明不会被提升到当前代码块顶部

function test(status) {
  if (status) {
    // console.log(res) // 结果 Cannot access 'res' before initialization,即 res 在此处还没定义不可访问
    let res = "blue";
    // console.log(res); // 结果 blue res 在此处可用
  } else {
    // console.log(res) // 结果 res is not defined,即 res 在此处无法访问
  }
  // console.log(res); // 结果 res is not defined,即 res 在此处无法访问
}
test(true); // 尝试传递 true 以及 false 分别试试

禁止重复声明

同一作用域下,不能重复声明一个已有的标识符

let name = "hohina";
var name = "yoko"; // 报错 Uncaught SyntaxError: Identifier 'name' has already been declared

for 循环中 let 声明的 i 每一轮都是新的 i

使用 let 声明的 i ,仅在块级作用域内有效,最后输出的是 6

var arr = [];
for (let i = 0; i < 10; i++) {
  arr[i] = function () {
    console.log(i);
    return i;
  };
}
arr[6](); // 结果 6

使用 var 声明的 i ,在全局作用域内有效,最后输出的是 10

var arr = [];
for (var i = 0; i < 10; i++) {
  arr[i] = function () {
    console.log(i);
    return i;
  };
}
arr[6](); // 结果 10

Q: 每一轮循环变量的 i 都是重新声明的,那么怎么知道上一轮循环的值,从而计算当前的值
A: js 引擎内部会记住上一轮的值,然后在上一轮的基础上进行初始化

for 循环中的 循环变量 i 与 内部变量 i 不在同一个作用域

  • 循环变量 i 在父作用域
  • 内部变量 i 在子作用域
for (let i = 0; i < 3; i++) {
  let i = "sass";
  console.log(i); // 结果 输出 3 遍 sass
}

父子作用域存在同名变量不会报错,但子作用域优先级高于父优先级,父作用域的同名变量将不再可以显式访问

for (let i = 0; i < 3; i++) {
  console.log(i); // 报错 Cannot access 'i' before initialization
  let i = "sass";
  console.log(i);
}
for (let i = 0; i < 3; i++) {
  console.log(i); // 结果 0 1 2
}
for (let i = 0; i < 3; i++) {
  console.log(i); // 0 1 2
  let o = "sass";
  console.log(o); // 结果 输出 3 遍 sass
}

三、作用链

使用当前作用域没有的变量或函数时,本级作用域没有,就向上级作用域查找,上级没有继续往上级的上级查找,这个链式查找的关系就是作用链

var a = 100;
function Func1() {
  var b = 200;
  function Func2() {
    var c = 300;
    console.log(a); // Func2 中找不到,向上一级 Func1 找,还是找不到,继续向上找,找到了变量 a ,值为 100
    console.log(b); // Func2 中找不到,向上一级 Func1 找,找到了变量 b ,值为 200
    console.log(c); // 直接在本级作用域找到了变量 c ,值为 300
  }
}

作用域中取到的值,取决于这个变量或函数“创建”的时候的值,而不是“调用”的时候

var a = 10;
function test() {
  var b = 20;
  function bar() {
    var c = a + b;
    console.log(c); // 输出 30
  }
  return bar;
}

b = 200; // 修改 b 的值

var x = test();
x(); // 相当于获取执行test函数的结果,test函数中定义的时候 b 为 20,所以后来 b = 200 的修改不会影响 bar 函数的执行结果

console.log(b); // 输出 200

四、作用域与上下文的区别

js执行分为“解释阶段”和“执行阶段”

解释阶段

  • 词法分析
  • 语法分析
  • 作用域规则规定

执行阶段

  • 创建执行上下文
  • 执行函数代码
  • 垃圾回收

作用域在解释阶段就已经确定了,不会改变,执行上下文则是在函数执行前创建的,随时有可能改变(比如this的指向)

一个作用域下

  • 可能包含若干个上下文环境
  • 可能从来没有过上下文环境(函数从来就没有被调用过)
  • 有可能有过上下文环境,又被被销毁了(现在函数被调用完毕后,上下文环境销毁)
  • 有可能同时存在一个或多个(闭包)

同一个作用域下,不同的调用会产生不同的执行上下文环境,继而产生不同的变量的值。

五、参考文献

  • https://github.com/mqyqingfeng/Blog/issues/3
  • https://juejin.cn/post/6844903797135769614
  • https://developer.mozilla.org/zh-CN/docs/Web/API/Window

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

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

相关文章

matlab绘图修改坐标轴数字字体大小及坐标轴自定义间隔设置

一、背景 在matlab使用plot函数绘图后&#xff0c;生成的图片坐标轴数字字体大小及间隔可能并不符合我们的要求&#xff0c;因此需要自定义修改&#xff0c;具体方法如下 二、修改坐标轴数字字体大小 只需添加以下命令即可&#xff1a; set(gca,FontName,Times New Roman,F…

echarts -- 柱状图之柱状条如何显示白色侧阴影且鼠标移入时高亮

有个图表是要求柱状条的右下侧显示一个白色的侧阴影&#xff0c;一直没找到合适的方法&#xff0c; 加border或者shadowColor都达不到需求的效果。 因为柱状图 中series里可以包含多组数据&#xff0c;有几组就代表一个系列中有几个数据。这就代表series里要写七组数据。 对于上…

你了解计算机网络的发展历史吗?

1.什么是计算机网络 计算机网络是指将一群具有独立功能的计算机通过通信设备以及传输媒体被互联起来的&#xff0c;在通信软件的支持下&#xff0c;实现计算机间资源共享、信息交换或协同工作的系统。计算机网络是计算机技术与通信技术紧密结合的产物&#xff0c;两者的迅速发展…

电阻如何读取阻值

前言&#xff1a;大家经常见到的贴片电阻上的丝印有纯数字、数字与R组合、数字与除R之外的字母组合的&#xff0c;但大家知不知道这样的标注与贴片电阻的i精度相关&#xff1f;同一个阻值因为精度不同&#xff0c;标注也会不同。例如封装为0805的贴片电阻&#xff0c;丝印473和…

STL-list的使用简介

目录 ​编辑 一、list的底层实现是带头双向循环链表 二、list的使用 1、4种构造函数&#xff08;与vector类似&#xff09;​编辑 2、迭代器iterator 3、容量&#xff08;capicity&#xff09;操作 4、element access 元素获取 5、增删查改 list modifiers 6、list的迭…

【计算机组成原理】-指令系统

&#x1f3b5;1.指令的发展 &#x1f308;1.1基础概念 计算机的程序是由一系列的机器指令组成的。指令就是要计算机执行某种操作的命令。从计算机的层次结构来说&#xff0c;有微指令&#xff0c;机器指令和宏指令之分。微程序中用到微指令&#xff0c;属于硬件&#xff0c;而…

Fluids —— MicroSolvers DOP

目录 Gas SubStep —— 重复执行对应的子步 Switch Solver —— 切换解算器 Gas Attribute Swap —— 交换、复制或移动几何体属性 Gas Intermittent Solve —— 固定时间间隔计算子解算器 Gas External Forces —— 计算外部力并更新速度或速度场 Gas Particle Separate…

D3121是什么?主要有哪些特点呢?为什么可以应用在车载音响系统上

D3121 是一块对地能动冲放大器集成电路&#xff0c;该电路能有效消除由线 路电阻所引起的问题及噪声。所需外围电容小&#xff0c;便于设计时小型化的同 时可靠性不降低。广泛应用于车载音响系统内。 D3121 系列采用 DIP8 、 SOP8 、 SIP8 的封装形式封装。 主要特点&#…

面试算法115:重建序列

题目 长度为n的数组org是数字1&#xff5e;n的一个排列&#xff0c;seqs是若干序列&#xff0c;请判断数组org是否为可以由seqs重建的唯一序列。重建的序列是指seqs所有序列的最短公共超序列&#xff0c;即seqs中的任意序列都是该序列的子序列。 例如&#xff0c;如果数组org为…

python绘制热力图-数据处理-VOC数据类别标签分布及数量统计(附代码)

前言 当你需要统计训练数据中每个类别标签有多少&#xff0c;并且想知道坐标中心分布在图像的位置信息时&#xff0c;你可以利用一下脚本进行计算&#xff01; 步骤 要绘制热力图来分析VOC数据的分布统计&#xff0c;可以按照以下步骤进行&#xff1a; 数据处理&#xff1…

移动通信系统关键技术多址接入MIMO学习(8)

1.Multiple-antenna Techniques多天线技术MIMO&#xff0c;从SISO到SIMO到MISO到如今的MIMO&#xff1b; 2.SIMO单发多收&#xff0c;分为选择合并、增益合并&#xff1b;SIMO&#xff0c;基站通过两路路径将信号发送到终端&#xff0c;因为终端接收到的两路信号都是来自同一天…

计算机速成课Crash Course - 18. 操作系统

今天继续计算机速成课Crash Course的系列讲解。 更多技术文章&#xff0c;全网首发公众号 “摸鱼IT” 锁定 -上午11点 - &#xff0c;感谢大家关注、转发、点赞&#xff01; 计算机速成课Crash Course - 17. 集成电路&摩尔定律 18. 操作系统 1940,1950 年代的电脑&#…

rime中州韵小狼毫 词组注释 滤镜

在rime中州韵小狼毫 联想词组 滤镜一文中&#xff0c;我们通过Filter滤镜功能配置了联想词组的功能&#xff0c;这使得我们在输入一些关键词汇时&#xff0c;可以联想补充一些附加的词组&#xff0c;例如我输入“手机”&#xff0c;就可以联想补充对应的手机号&#xff0c;如下…

Kali Linux —— 漏洞分析工具

Cisco-torch与Global Exploiter专攻Cisco漏洞 一、Cisco 工具 Kali 有许多工具&#xff0c;比如信息收集工具、密码爆破工具等等&#xff0c;还有一些可用于攻击 Cisco 路由器的工具。Cisco-torch就是这样&#xff0c;用于大规模扫描、指纹识别和利用的工具之一。 打开终端控…

关于CAD导入**地球的一些问题讨论

先上示例: 上图是将北京王佐停车场的红线CAD图导入到图新地球效果,如果看官正是需要这样的效果,那么请你继续往下看,全是干货! 在地球中导入CAD图可以做为电子沙盘。对于工程人来说,是极有帮助的。以前一直用谷歌地球,大约在2020年左右,就被和谐了。当时感觉挺可惜的。…

[渗透测试学习] Surveillance -HackTheBox

文章目录 信息搜集getshell提权信息搜集 nmap扫描端口 nmap -sV -sC -v -p- --min-rate 1000 10.10.11.245扫出来两个端口,其中80端口有http服务并且重定向到surveillance.htb 那么我们添加下域名然后访问80端口,发现是企业网站尝试扫描子域名和目录无果后,用Wappalyzer插…

【STM32】HAL库的STOP低功耗模式UART串口唤醒BUG,第一个接收字节出错的问题(尚未解决,疑难杂症)

【STM32】HAL库的STOP低功耗模式UART串口唤醒BUG&#xff0c;第一个接收字节出错的问题&#xff08;尚未解决&#xff0c;疑难杂症&#xff09; 文章目录 BUG复现调试代码推测原因及改进方案尝试中断时钟供电外设唤醒方式校验码硬件问题 切换到STOP0模式尝试最终结论和猜想附录…

社区团购配送超市与小程序的共赢之路

对于社区服务来说&#xff0c;搭建一个小程序可以提供更加便捷、高效的服务&#xff0c;提升用户体验。下面我们将详细介绍如何通过乔拓云第三方平台搭建一个社区团购小程序。 首先&#xff0c;你需要打开乔拓云第三方平台&#xff0c;这是一个专门为小程序开发提供的平台。在浏…

戴尔服务器有8条内存条,开机有一条内存条自检提示出错,可以不用管他吗,有影响吗?

环境 戴尔R730 问题描述 戴尔服务器有8条内存条&#xff0c;开机有一条内存条自检提示出错&#xff0c;可以不用管他吗&#xff0c;有影响吗&#xff1f; 提示B1内存有问题 解决方案 不能&#xff0c;有影响&#xff0c;安装系统时卡住在启动节目无法正常安装&#xff0c;…

【PyQt5设计】:自动点击神器 - 解决重复性的点击和输入操作

文章目录 自动点击神器介绍测试窗口介绍自动点击神器的使用教程资源领取注意事项 自动点击神器介绍 本次使用PyQt5设计的【自动点击神器】旨在解决重复性的点击工作&#xff0c;解放双手&#xff0c;具有及时性和准确性&#xff0c;可选择坐标位置或图片两种方式实现鼠标的定位…