JS进阶-作用域

学习目标:

  • 掌握作用域

学习内容:

  1. 作用域
  2. 局部作用域
  3. 全局作用域
  4. 作用域链
  5. JS垃圾回收机制
  6. 拓展-JS垃圾回收机制-算法说明
  7. 闭包
  8. 变量提升

作用域:

作用域规定了变量能够被访问的"范围",离开了这个"范围"变量便不能被访问。
作用域分为:

  1. 局部作用域
  2. 全局作用域

局部作用域:

局部作用域分为函数作用域和块作用域。

  • 函数作用域:

在函数内部声明的变量只能在函数内部被访问,外部无法直接访问。

 <script>
    function getSum() {
      //函数内部是函数作用域  属于局部变量
      const num = 10
    }
    console.log(num)  //此处报错,函数外部不能使用局部作用域变量
  </script>

总结:

  1. 函数内部声明的变量,在函数外部无法被访问。
  2. 函数的参数也是函数内部的局部变量。
  3. 不同函数内部声明的变量无法互相访问。
  4. 函数执行完毕后,函数内部的变量实际被清空了。
  • 块级作用域:

在JavaScript中使用{ }包裹的代码称为代码块,代码块内部声明的变量外部将【有可能】无法被访问。

 <script>
    // for (var i = 1; i <= 3; i++) {
    //   console.log(i)
    // }
    // console.log(i)

    // for (let i = 1; i <= 3; i++) {
    //   // 块作用域
    //   console.log(i)
    // }
    // for (let i = 1; i <= 3; i++) {
    //   // 块作用域
    //   console.log(i)
    // }

    if (true) {
      let i = 10
    }
    console.log(i)  //报错,外部无法被访问到
  </script>

总结:

  1. let声明的变量会产生块级作用域,var不会产生块级作用域。
  2. const声明的常量也会产生块作用域。
  3. 不同代码之间的变量无法互相访问。
  4. 推荐使用letconst
  • 小结:

1.局部作用域分为哪两种?

局部作用域说明
函数作用域函数内部
块级作用域{ }

2.局部作用域声明的变量外部能使用吗?

不能

全局作用域:

<script>标签.js文件的【最外层】就是所谓的全局作用域,在此声明的变量在函数内部也可以被访问。

全局作用域中声明的变量,任何其它作用域都可以被访问。

 <script>
    //全局作用域
    //全局作用域下声明了num变量
    const num = 10
    function fn() {
      //函数内部可以使用全局作用域的变量
      console.log(num)
    }
    //此处全局作用域
  </script>

注意:

  1. 为window对象动态添加的属性默认也是全局的,不推荐!!!
  2. 函数中未使用任何关键字声明的变量为全局变量,不推荐!!!!
  3. 尽可能少的声明全局变量,防止全局变量被污染。
  • 小结:

1.全局作用域有哪些?

<script>标签内部-
.js文件-

2.全局作用域声明的变量其他作用域能使用吗?

相当能

JavaScript中的作用域是程序被执行时的底层机制,了解这一机制有助于规范代码书写习惯,避免因作用域导致的语法错误。


作用域链:

作用域本质上是底层的变量查找机制

在函数被执行时,会优先查找当前函数作用域中查找变量。

如果当前作用域查找不到则会依次逐级查找父级作用域直到全局作用域。

 <script>
    //全局作用域
    let a = 1
    let b = 2
    //局部作用域
    function f() {
      let a = 1
      //局部作用域
      function g() {
        a = 2
        console.log(a)
      }
      g() //调用g
    }
    f() //调用f
  </script>

从小到大
总结:

  1. 嵌套关系的作用域串联起来形成了作用域链。
  2. 相同作用域链中按着从小到大的规则查找变量。
  3. 子作用域能够访问父作用域,父级作用域无法访问子级作用域。
  • 小结:

1.作用域链本质是什么?

作用域本质上是底层的变量查找机制。

2.作用域查找的规则是什么?

会优先查找当前函数作用域中查找变量。
查找不到则会依次逐级查找父级作用域直到全局作用域。

JS垃圾回收机制:

垃圾回收机制简称GC。

JS中内存的分配和回收都是自动完成的,内存在不使用的时候会被垃圾回收器自动回收。

  • 内存的生命周期:

JS环境中分配的内存,一般有如下生命周期

  1. 内存分配:当我们声明变量、函数、对象的时候,系统会自动为他们分配内存。
  2. 内存使用:即读写内存,也就是使用变量、函数等。
  3. 内存回收:使用完毕,由垃圾回收器自动回收不再使用的内存。
  • 说明:

全局变量一般不会回收(关闭页面回收)。

一般情况下局部变量的值,不用了,会被自动回收掉。

  • 内存泄漏:程序中分配的内存由于某种原因程序未释放无法释放叫做内存泄漏
<script>
    for (let i = 1; i <= 3; i++) {
 
    }
    let num = 10
    function fn() {
      const str = 'andy'
      // str = 'lily'
      console.log(str)
    }
    fn()
    fn()
    fn()
  </script>
  • 小结:

1.什么是垃圾回收机制?

简称GC。
JS中内存的分配和回收都是自动完成的,内存在不使用的时候会被垃圾回收器自动回收。

2.什么是内存泄漏?

不再用到的内存,没有及时释放,就叫做内存泄漏。

3.内存的生命周期是什么样的?

内存分配、内存使用、内存回收。
全局变量一般不会回收;一般情况下局部变量的值,不用了,会被自动回收掉。

拓展-JS垃圾回收机制-算法说明:

堆栈空间分配区别:

  1. 栈(操作系统):由操作系统自动分配释放函数的参数值、局部变量等,基本数据类型放到栈里面。
  2. 堆(操作系统):一般由程序员分配释放,若程序员不释放,由垃圾回收机制回收。复杂数据类型放到堆里面。

下面介绍两种常见的浏览器垃圾回收算法:引用计数法标记清除法

  • 引用计数:

IE采用的引用计数算法,定义“内存不再使用”,就是看一个对象是否有指向它的引用,没有引用了就回收对象。

算法:

  1. 跟踪记录被引用的次数
  2. 如果被引用了一次,那么就记录次数1,多次引用会累加 ++
  3. 如果减少一个引用就减1 --
  4. 如果引用次数是0,则释放内存。

在这里插入图片描述
在这里插入图片描述
由上面可以看出,引用计数算法是个简单有效的算法。

但它却存在一个致命的问题:嵌套引用(循环引用)。

如果两个对象相互引用,尽管他们已不再使用,垃圾回收器不会进行回收,导致内存泄漏。

在这里插入图片描述

因为他们的引用次数永不会是0。这样的相互引用如果说很大量的存在就会导致大量的内存泄漏。

  • 标记清除法:

现代的浏览器已经不再使用引用计数算法了。

现代浏览器通用的大多是基于标记清除算法的某些改进算法,总体思想都是一致的。

核心:

  1. 标记清除算法将“不再使用的对象”定义为“无法达到的对象”。
  2. 就是从根部(在JS中就是全局对象)出发定时扫描内存中的对象。凡是能从根部到达的对象,都是还需要使用的。
  3. 那些无法由根部出发触及到的对象被标记为不再使用,稍后进行回收

在这里插入图片描述
在这里插入图片描述
根部已经访问不到,所以自动清除。

  • 小结:

1.标记清除法核心思路是什么?

从根部扫描对象,能查找到的就是使用的,查找不到的就要回收。

闭包:

概念:一个函数对周围状态的引用捆绑在一起,内层函数中访问到其外层函数的作用域。

简单理解:闭包 = 内层函数 + 外层函数的变量

  • 闭包作用:封闭数据,提供操作,外部也可以访问函数内部的变量。
<script>
    // //简单的写法
    // function outer() {
    //   let a = 10
    //   function fn() {
    //     console.log(a)
    //   }
    //   fn()
    // }
    // outer()


    //常见的闭包的形式  外部可以访问使用  函数内部的变量
    function outer() {
      let a = 10
      function fn() {
        console.log(a)
      }
      return fn
    }

    // outer() === fn ===  function fn() {}
    // const fun = function fn(){}
    // const fun = outer()

    //常见的写法2
    // function outer() {
    //   let a = 100
    //   return function () {
    //     console.log(a)
    //   }
    // }
    // const fun = outer()
    // fun()  // 调用函数

    //外面要使用这个10
 </script>
  • 闭包应用:实现数据的私有。
<script>
 //闭包的应用
    //普通形式  统计函数调用的次数
    // let i = 0
    // function fn() {
    //   i++
    //   console.log(`函数被调用了${i}次`)
    // }
    //因为i是全局变量,容易被修改
    
    //闭包形式 统计函数调用的次数
    function count() {
      let i = 0
      function fn() {
        i++
        console.log(`函数被调用了${i}`)
      }
      return fn
    }
    const fun = count()
  </script>
  • 小结:

1.怎么理解闭包?

闭包 = 内层函数 + 外层函数的变量。

2.闭包的作用?

封闭数据,实现数据私有,外部也可以访问函数内部的变量。
闭包很有用,因为它允许将函数与其所操作的某些数据(环境)关联起来。

3.闭包也可能引起的问题?

内存泄漏。

变量提升:

变量提升是 JavaScript 中比较“奇怪”的现象,它允许在变量声明之前即被访问(仅存在于var声明变量)。

  • 注意:
  1. 变量在未声明即被访问时会报语法错误。
  2. 变量在var声明之前即被访问,变量的值为undefined
  3. let/const 声明的变量不存在变量提升。
  4. 变量提升出现在相同作用域当中。
  5. 实际开发中推荐先声明再访问变量
<script>
    // 1. 把所有var声明的变量提升到 当前作用域的最前面
    // 2. 只提升声明, 不提升赋值
    // var num
    // console.log(num + '件')
    // num = 10
    // console.log(num)

    function fn() {
      console.log(num)
      var num = 10
    }
    fn()
  </script>
  • 说明:

JS初学者经常花很多时间才能习惯变量提升,还经常出现一些意想不到的bug,正因为如此,ES6 引入了块级作用域,用let 或者 const声明变量,让代码写法更加规范和人性化。

  • 小结:

1.用哪个关键字声明变量会有变量提升?

  var

2.变量提升是什么流程?

先把var变量提升到当前作用域于最前面。
只提升变量,不提升变量赋值。
然后依次执行代码。

我们不建议使用var声明变量。

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

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

相关文章

批量爬取B站网络视频信息

使用XPath爬取B站视频链接等相关信息 分析B站html框架获取内容完整代码 对于B站&#xff0c;目前网上的爬虫大多都是使用通过解析服务器的响应来爬取想要的内容&#xff0c;下面我们通过使用XPath来爬取B站上一些想要的信息 此次任务我们需要对B站搜索到的关键字&#xff0c;并…

本地多卡(3090)部署通义千问Qwen2-72B大模型提速实践:从龟速到够用

最近在做文本风格转化&#xff0c;涉及千万token级别的文本。想用大模型转写&#xff0c;在线的模型一来涉及数据隐私&#xff0c;二来又不想先垫钱再找报销。本地的7-9B小模型又感觉效果有限&#xff0c;正好实验室给俺配了4卡3090的机子&#xff0c;反正也就是做个推理&#…

Python falsk 接口挂载 步骤

Python falsk 接口挂载 步骤 1.首先要有自己独立的python环境&#xff0c;因为如果和别人共用环境的话&#xff0c;会有依赖包冲突的情况 2.找到python.exe的安装路径 3.CMD切换到该路径下 4.执行指令activate,进入到专属的python环境 5.然后执行指令 pip freeze > re.tet…

CentOS 7遗忘了root密码怎么办?

正文共&#xff1a;666 字 12 图&#xff0c;预估阅读时间&#xff1a;1 分钟 说来也巧&#xff0c;突然发现使用KVM在部署CentOS时&#xff08;笔记本电脑安装CentOS系统&#xff09;&#xff0c;会有一个神奇的现象&#xff0c;还不是偶然出现的&#xff0c;在最近的三四次部…

【ComfyUI节点】扰动注意力引导Perturbed Attention Guidance

扰动注意力引导 Perturbed Attention Guidance GitHub - KU-CVLAB/Perturbed-Attention-Guidance: Official implementation of "Perturbed-Attention Guidance" 按照官方介绍&#xff0c;扰动注意力指导显著提高了扩散模型的样本质量&#xff0c;而无需外部条件&am…

测试用例编写与管理流程

hello&#xff0c;大家好&#xff0c;我是一名测试开发工程师&#xff0c;至今已在自动化测试领域深耕9个年头&#xff0c;现已将本人实战多年的多终端自动化测试框架【wyTest】开源啦&#xff0c;在接下来的一个月里&#xff0c;我将免费指导大家使用wyTest&#xff0c;请大家…

14-Django项目--文件上传-Excel

目录 前端 路由 视图函数 前端 <div class"modal-body"><form method"post" enctype"multipart/form-data" action"/pretty/asset/">{% csrf_token %}<input type"file" name"excel"><bu…

Leetcode3194. 最小元素和最大元素的最小平均值

Every day a Leetcode 题目来源&#xff1a;3194. 最小元素和最大元素的最小平均值 解法1&#xff1a;排序遍历 将数组 nums 排序后&#xff0c;利用双指针计算每一对 (minElement maxElement) / 2&#xff0c;最小值即为答案。 代码&#xff1a; /** lc appleetcode.cn …

Spring源码十七:Bean实例化入口探索

上一篇Spring源码十六&#xff1a;Bean名称转化我们讨论doGetBean的第一个方法transformedBeanName方法&#xff0c;了解Spring是如何处理特殊的beanName&#xff08;带&符号前缀&#xff09;与Spring的别名机制。今天我们继续往方法下面看&#xff1a; doGetBean 这个方法…

AI 大模型系统实战

AI 大模型是什么&#xff1f; 维基百科对基础模型的定义是这样的&#xff0c;基础模型是一种大型机器学习模型&#xff0c;通常在大量数据上进行大规模训练&#xff08;通过自监督学习或半监督学习&#xff09;&#xff0c;以使它可以适应各类下游任务。因此&#xff0c;它需要…

数学系C++ 类与对象 STL(九)

目录 目录 面向对象&#xff1a;py&#xff0c;c艹&#xff0c;Java都是,但c是面向过程 特征&#xff1a; 对象 内敛成员函数【是啥】&#xff1a; 构造函数和析构函数 构造函数 复制构造函数/拷贝构造函数&#xff1a; 【……】 实参与形参的传递方式&#xff1a;值…

【Java】了解异常

初始异常 我们平时应该已经接触过一些 “异常” 了&#xff0c;这里列举一些例子。 算术异常&#xff1a; 数组下标越界异常&#xff1a; 访问空指针异常&#xff1a; 所谓异常指的就是程序在 运行时 出现错误时通知调用者的一种机制。 异常的基本用法 捕获异常 try{ 有可能…

知识的向量表示

1、one-hot表示&#xff0c;空间太大 2、bag词袋模型&#xff0c;无法表示词的语义 3、词的语义由什么决定&#xff1f;词由他的上下文决定&#xff1f;分布式语义 4、CBow&#xff0c;通过前面几个词和后面几个词&#xff0c;预测中间几个词 5、skip-gram&#xff0c;通过…

【Python】已解决:(MongoDB安装报错)‘mongo’ 不是内部或外部命令,也不是可运行的程序

文章目录 一、分析问题背景二、可能出错的原因三、错误代码示例四、正确代码示例及解决方案五、注意事项 已解决&#xff1a;&#xff08;MongoDB安装报错&#xff09;‘mongo’ 不是内部或外部命令,也不是可运行的程序 一、分析问题背景 在安装和配置MongoDB时&#xff0c;有…

数据库逆向工程工具reverse_sql

reverse_sql 是一个用于解析和转换 MySQL 二进制日志&#xff08;binlog&#xff09;的工具。它可以将二进制日志文件中记录的数据库更改操作&#xff08;如插入、更新、删除&#xff09;转换为反向的 SQL 语句&#xff0c;以便对系统或人为产生的误操作进行数据回滚和恢复。 *…

Python28-9 XGBoost算法

XGBoost&#xff08;eXtreme Gradient Boosting&#xff0c;其正确拼写应该是 "Extreme Gradient Boosting"&#xff0c;而XGBoost 的作者在命名时故意使用了不规范的拼写&#xff0c;将“eXtreme”中的“X”大写&#xff0c;以突出其极限性能和效率&#xff09;是一…

【open3d专栏】利用PCA计算狭长点云的主方向

在点云处理中&#xff0c;PCA通常用于识别数据集中的主要方向&#xff0c;从而帮助理解数据的几何结构。 使用工具&#xff1a;python&#xff0c;open3d库 目的&#xff1a;计算狭长型点云的主方向 # -*- coding: utf-8 -*- """ Created on Sun Jul 7 11:50…

SpringMVC源码解析(一):web容器启动流程

SpringMVC源码系列文章 SpringMVC源码解析(一)&#xff1a;web容器启动流程 目录 一、SpringMVC全注解配置1、pom文件2、web容器初始化类(代替web.xml)3、SpringMVC配置类(代替springmvc.xml)4、测试Controller 二、SpringServletContainerInitializer1、web容器初始化入口2、…

RNN 交叉熵

RNN善于处理时序 序列数据 简单RNN 展开就是 LSTM 遗忘门f_t决定上期记忆保留多少 隐藏层 在神经网络中&#xff0c;隐藏层指的是除了输入层和输出层之外的层&#xff0c;它们的输出不会直接用于网络的最终输出&#xff0c;而是作为中间步骤用于提取和转换数据。因此&#x…

LabVIEW光谱测试系统

在现代光通信系统中&#xff0c;光谱分析是不可或缺的工具。开发了一种基于LabVIEW的高分辨率光谱测试系统&#xff0c;通过对可调谐激光器、可编程光滤波器和数据采集系统的控制&#xff0c;实现了高效、高精度的光谱测量。 项目背景 随着光通信技术的迅速发展&#xff0c;对…