JavaScript中var,let,const 的区别

JavaScript中var,let,const 的区别

  • 一、前言
  • 二、使用var声明变量
    • 1、var 声明的变量是函数作用域
    • 2、var声明的变量会有变量提升
    • 3、全局作用域中声明的变量会被挂载到全局对象的window中
    • 4、同一作用域下,可以重复声明相同的变量名
  • 三、使用let声明变量
    • 1、使用let声明的变量具有块级作用域的特点
    • 2、let声明的变量有暂时性死区,没有变量提升,必须先声明再使用
    • 3、全局作用域中使用let声明的变量不会挂载到window对象中
    • 4、同一作用域下不能使用let重复声明相同的变量
  • 四、使用const声明常量
    • 1、const声明常量必须赋初始值
    • 2、const声明的常量不能更改
  • 五、声明变量的其他方式
  • 六、应用实例
    • 1、for循环中的let和var
    • 2、for循环结合定时器
    • 3、const的使用
  • 七、推荐使用的声明方式
    • 1、不推荐使用var,推荐使用let和const
    • 2、优先使用const,其次是let
  • 八、总结

一、前言

自ES6(ECMAScript2015)出来后,JavaScript中又多了两种声明变量的关键字,let和const;但是const声明的变量通常是常量,因为一旦声明便不可改变。那么这三种方式使用哪一种比较好呢?它们之间又有什么区别呢?接下来说一下我的理解。

二、使用var声明变量

var是ECMAScript规范中最早用于声明变量的关键字,一直延用自今。但是自从ES6规范中又增加了两种方式之后,var声明变量再也不是唯一的和最佳的选择了。那么var声明的变量到底有什么特点呢?

1、var 声明的变量是函数作用域

var声明的变量具备函数作用域的特点,在函数内部声明的变量只能在函数作用域内部使用,在函数外部不能访问。但是,在函数内部可以访问函数外部的全局作用域中的变量。关于这一点,可以详细学习一下作用域和作用域链。这里不在赘述。

	<script>var num="333";function fun(){var age=23;//在函数内部声明,在函数外部不能访问console.log(age)//23console.log(num);//333,函数内部可以访问全局作用域中的变量num}fun();console.log(age);//报错Uncaught ReferenceError: age is not defined,不能访问函数内部的变量</script>

2、var声明的变量会有变量提升

在全局作用域中,var声明的变量会被提升到全局作用域的最顶端,在局部作用域中声明的变量会被提升到局部作用域的最顶端

 	<script>console.log(num);//undefinedvar num="333";function fun(){console.log(age);//undefinedvar age=23;}fun();</script>

在上面这段代码中,定义了一个全局变量num,在函数fun中定义可一个局部变量age。但是,都是在变量被声明之前使用打印变量num和age的。但是结果并没有报错,而是undefined。说明变量num和age都被提升到变量当前作用域中的最顶端了。可以在变量声明之前使用变量。但是没有多大的意义。

虽然两个变量在声明的时候都赋有初始值,但是初始值并没有没打印出来。这是因为,使用var声明的变量会被提升,但是但是变量的赋值并不会被提升

3、全局作用域中声明的变量会被挂载到全局对象的window中

以下这段代码分别打印:96,96,true。

	<script>var num=96;console.log(num)//96console.log(window.num);//96console.log(num===window.num)//true</script>

4、同一作用域下,可以重复声明相同的变量名

同一个作用域下可以使用var声明相同名称的变量,前面的值会被后面的值覆盖,使用时使用最后声明的变量

	<script>var a=23;var a=56;var a=98;console.log(a);//98</script>

三、使用let声明变量

1、使用let声明的变量具有块级作用域的特点

ES6 新增的 let 关键字跟 var 很相似,但它的作用域是块级的,这也是 JavaScript 中的新概念。块级作用域由最近的一对包含花括号{}界定。换句话说,if 块、while 块、function 块,甚至连单独 的块也是 let 声明变量的作用域。在变量的作用域之外,无法访问变量,会报错

	<script>{let num='36';console.log(num);//36}console.log(num);//报错:ReferenceError if(true){let num1=23;console.log(num1);//23}console.log(num1);//报错:ReferenceError while(true){let num3=69;}console.log(num3);//报错:ReferenceError function fun(){let num4=65;}console.log(num4)//报错:ReferenceError </script>

2、let声明的变量有暂时性死区,没有变量提升,必须先声明再使用

这一点与var有区别,let声明的变量必须先声明再使用。未经声明就使用,会报错,在 let 声明之前的执行瞬间被称为“暂时性死区”,在此阶段引用任何后面才声明的变量都会抛出 ReferenceError。

<script>console.log(num)//报错ReferenceErrorlet num=96;{console.log(a);//报错ReferenceErrorlet a=6;}</script>

3、全局作用域中使用let声明的变量不会挂载到window对象中

这一点和var也不一样。let声明的全局变量不会放在window中。以下代码分别输出666,undefined,false

	<script>let num=666;console.log(num);//666console.log(window.num);//undefinedconsole.log(num===window.num);//false</script>

4、同一作用域下不能使用let重复声明相同的变量

在相同的额作用域下,相同的变量名不能使用let重复声明,会报错。但是不同作用域下不受限制
同一作用域下不能使用let重复声明变量

	<script>let num=66;let num=33;//报错,SyntaxError,相同作用域下不能重复声明变量</script>

不同作用域下,let可以声明相同变量名的变量

 <script>let num=66;function fun(){let num=65;{let num=63;console.log(num);//63}console.log(num);//65};console.log(num);//66fun();</script>

相同作用域下不能重复声明并不受var关键字的限制

<script>var a=66;var a=99;let a=33;//报错SyntaxError
</script>

在上面这段代码中,虽然变量a是使用var关键字声明的,但是在同一作用域下再次使用let声明a变量,依然会报错,不能重复声明

四、使用const声明常量

除了 let,ES6 同时还增加了 const 关键字。使用 const 声明的变量必须同时初始化为某个值。 一经声明,在其生命周期的任何时候都不能再重新赋予新值。

1、const声明常量必须赋初始值

<script>const a=6;//合法有效const b;//报错 SyntaxError,必须赋初始值才可以
</script>

2、const声明的常量不能更改

<script>const a=6;//合法有效a=7;//报错,不能更改
</script>

对于const声明的原始数据类型,一旦声明变不能更改,但是对于引用数据类型,虽然不能重新赋值给某个新的引用类型变量。但是操作操作引用数据类型变量中的元素或者属性却是合法的。因为这些操作不会改变引用数据类型的地址。

<script>const obj={};let o={};//obj=o;//报错obj.name="南山行者";//合法有效console.log(obj);const arr=[1,2,3];//arr=obj;//报错arr.push(3);//合法有效arr.shift();//合法有效console.log(arr);
</script>

const除以上这两点不同之外,其他的特性与let的特性一致,也是具有块级作用域、变量不能提升,同一个作用域下不能重复声明等特点。

五、声明变量的其他方式

在JavaScript中还有一种声明变量的方式,那就是不使用任何的关键字,直接赋值,这种方式声明的变量通常被称为隐式全局变量,会被挂载到全局对象的window中。但是在实际的开发中不推荐这种方式,因为这种方式声明的变量挂载在全局对象中,不容易被垃圾回收机制回收,容易造成内存泄露

 <script>function fun(){age=32;}fun();console.log(age);//32console.log(window.age);//32console.log(window.age===age);//true{num=66;}console.log(num)//66console.log(window.num)//66console.log(window.num===num)//true</script>

在上面这段代码中,变量age和num都不是使用关键字声明的,也不是声明再全局中变量,但是在全局中却可以访问。因为不使用var,let,const关键字声明的变量叫隐式全局变量,挂载到全局对象window中。全局作用域包含的其他任何作用域中都可以访问到。实际开发中应该尽量避免这种声明方式。

六、应用实例

1、for循环中的let和var

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

在let出现之前,都是使用var声明变量,而var申明的变量是函数作用域的,for循环并不是函数,所以var声明的变量会泄露到循环体的外部。如上面这段代码,在for循环外部输出变量i得到的结果是5。是循环体执行结束之后的结果。

但是使用let就不会有这种现象,因为let声明的变量是块级作用域,只能在循坏体内部的块作用域中被访问使用,在循环体外部访问会报错,也就是说,在for循环中使用let声明变量,不会泄露到循环体外部

<script>for(let i=0;i<5;i++){}console.log(i);//报错,访问不到
</script>

2、for循环结合定时器

<script>for (var i = 0; i < 5; ++i) { setTimeout(() =>{ console.log(i)//5,5,5,5,5}, 1000) }
</script>

上面这段代码,很多初学者可能会认为输出0,1,2,3,4。然而并不是,结果输出的是5,5,5,5,5

之所以会这样是因为,setTimeout定时器会在循环结束之后再执行,因为定时器是异步的操作,循环会先于它执行完毕。当循环执行完了之后,循环退出时,保存的变量的值就是循环执行结束的值:5。这个时候再去执行setTimeout的延时操作,获取的变量i都是同一个值5。

如果将循环变量i使用let声明,结局会完全不同,因为let是块级作用域的。JavaScript引擎会给每个循环生成一个新的循环变量保存在对应的块级作用域中。每个setTimeout引用的都是不同变量的实例。所以输出的结果就是循环执行过程中每个循环变量的值:0,1,2,3,4

<script>for (let i = 0; i < 5; ++i) { setTimeout(() =>{ console.log(i)}, 1000) }
</script>

3、const的使用

当我们只想声明一个在使用中不被修改的变量时,推荐使用const,比如:for…in和for…of循环

<script>for (const k in {a: 1, b: 2,c:3}) { console.log(k); } // a, b ,cfor (const v of ["行者",23,69,"学习"]) { console.log(v); } // 行者, 23, 69,学习
</script>

当然,这两个例子只是特例,并不是只有这两种情况才可以使用,在实际开发中,优先推荐使用const

七、推荐使用的声明方式

1、不推荐使用var,推荐使用let和const

有了 let 和 const,优先使用 let 和 const 有助于提升代码质量,因为变量有了明确的作用域、声明位置,以及不变的值。

2、优先使用const,其次是let

使用 const 声明可以让浏览器运行时强制保持变量不变,也可以让静态代码分析工具提前发现不 合法的赋值操作。推荐优先使用 const 来声明变量,只在提前知道未来会有修改时,再使用 let。这样可以推断某些变量的值永远不会变,同时也能迅速发现因 意外赋值导致的非预期行为或报错。

八、总结

计算机领域的知识日新月异,技术更新非常迅速,想要在这个领域常足发展,保持自己的行业竞争力,需要我们时常关注行业技术的革新,不断的去学习。但是知识点是死的,人是活的,在具体使用技术知识点的过程中,要根据实际的需求合理选用技术。因为在编程行业,没有完美的方案,只有趋于完美的方案。

以上是我在实际的开发和使用中对于var,let和const的理解。虽有心尽力表达完善和正确,但是难免会有疏漏。若有发现表达不当之处,欢迎交流指正。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Unity下如何实现RTMP或RTSP播放端录像?

好多开发者问我们&#xff0c;Unity环境下&#xff0c;除了RTSP或RTMP的播放&#xff0c;如果有录像诉求&#xff0c;怎么实现&#xff1f;实际上录像相对播放来说&#xff0c;更简单一些&#xff0c;因为不涉及到绘制&#xff0c;只要拉流下来数据&#xff0c;直接写mp4文件就…

云原生Kubernetes:pod资源管理与配置

目录 一、理论 1.pod 2.pod容器分类 3.镜像拉取策略 4.pod 的重启策略 二、实验 1.Pod容器的分类 2.镜像拉取策略 三、问题 1.apiVersion 报错 2.pod v1版本资源未注册 3.格式错误 4.取行显示指定pod信息 四、总结 一、理论 1.pod (1) 概念 Pod是kubernetes中…

【LeetCode-中等题】78. 子集

文章目录 组合并集问题汇总&#xff1a;题目方法一&#xff1a;动态规划方法二&#xff1a;递归加回溯(关键----startIndex) 组合并集问题汇总&#xff1a; 1、子集去重版本 2、组合非去重版本 3、组合去重版本 题目 注意&#xff1a;这里的nums数组里面的元素是各不相同的&a…

(文末赠书)我为什么推荐应该人手一本《人月神话》

能点进来的朋友&#xff0c;说明你肯定是计算机工作的朋友或者对这本书正在仔细琢磨着的朋友。 文章目录 1、人人都会编程的时代&#xff0c;我们如何留存?2、小故事说明项目管理着为什么必看这本书3、如何评价《人月神话&#xff1a;纪念典藏版》4、本书的目录&#xff08;好…

【操作系统】进程的通信IPC

进程通信是指进程之间的信息交换。 低级通信方式&#xff1a;PV操作 高级通信方式&#xff1a;1.共享存储2.消息传递3.管道通信 共享存储 低级数据结构共享&#xff0c;高级存储区共享。 对共享空间进行读写操作时&#xff0c;需要用到互斥工具。 消息传递 利用发送消息和…

如何选择安全稳定的大文件传输软件平台,企业传输必看

在当今的信息时代&#xff0c;大文件传输是企业间合作、项目交付、数据备份等场景中不可或缺的需求。然而&#xff0c;大文件传输也面临着诸多挑战&#xff0c;比如速度慢、不稳定、不安全等&#xff0c;给企业带来了不少困扰和风险。那么&#xff0c;如何选择一款安全稳定的大…

自然语言处理应用(一):情感分析

情感分析 随着在线社交媒体和评论平台的快速发展&#xff0c;大量评论的数据被记录下来。这些数据具有支持决策过程的巨大潜力。 情感分析&#xff08;sentiment analysis&#xff09;研究人们在文本中 &#xff08;如产品评论、博客评论和论坛讨论等&#xff09;“隐藏”的情…

echarts静态饼图

<div class"cake"><div id"cakeChart"></div></div> import * as echarts from "echarts";mounted() {this.$nextTick(() > {this.getCakeEcharts()})},methods: {// 饼状图getCakeEcharts() {let cakeChart echart…

『力扣每日一题07』字符串最后一个单词的长度

气死我啦&#xff0c;今天这道题花了快一个小时&#xff0c;我学完了答案的解法&#xff0c;放上去在线 OJ &#xff0c;一直报错&#xff0c;找来找去都找不到自己错在哪&#xff0c;明明跟答案一模一样。后来还是学了另一种解法&#xff0c;才跑出来的(̥̥̥̥̥̥̥̥o̥̥…

UE5 Foliage地形植被实例删不掉选不中问题

目前问题测试发生在5.2.1上 地形上先填充后刷的植被删不掉 首先这个就是bug&#xff0c;大概看到说是5.3上能解决了&#xff0c;对此我只能吐槽ue5上地形植被bug太多了 什么nanite还能产生bug&#xff0c;不过这次又不是&#xff0c;整个删掉instance可以删除所有植被&#…

【踩坑纪实】URL 特殊字符 400 异常

URL 特殊字符 400 异常 笔者之前在写后端或者前端时&#xff0c;在处理表单时&#xff0c;经常有对特殊字符的检验处理&#xff0c;但自己也不清楚为什么要这么做&#xff0c;浅浅地以为可能是特殊字符不好看或者存取可能会造成异常&#xff1f;不过一直没遇到过问题&#xff…

uniapp微信小程序《隐私保护协议》弹窗处理流程

背景 《关于小程序隐私保护指引设置的公告》 《小程序隐私协议开发指南》 流程 1.第一步 必须设置且审核通过&#xff01;&#xff01;&#xff01; 2.第二步 uniapp在manifest.json中添加&#xff01;&#xff01;&#xff01; /* 在 2023年9月15号之前&#xff0c;在 ap…

玩转Mysql系列 - 第14篇:详解事务

环境&#xff1a;mysql5.7.25&#xff0c;cmd命令中进行演示。 开发过程中&#xff0c;会经常用到数据库事务&#xff0c;所以本章非常重要。 本篇内容 什么是事务&#xff0c;它有什么用&#xff1f; 事务的几个特性 事务常见操作指令详解 事务的隔离级别详解 脏读、不可…

Dockerfile 制作常用命令总结

1.FROM( from ) : FROM : from 表示选择一个镜像作为基础镜像&#xff08;在一个Dockerfile 中可以使用多条from&#xff0c;来构建多个镜像&#xff09; 2.ENV &#xff1a; 用来在镜像创建出的容器中声明环境变量&#xff0c;如&#xff1a; ENV PYTHONIOENCODINGutf-8 …

Leetcode算法入门与数组丨3. 数组基础

文章目录 前言1 数组简介2 数组的基本操作2.1 访问元素2.2 查找元素2.3 插入元素2.4 改变元素2.5 删除元素 3 总结task03task04 前言 Datawhale组队学习丨9月Leetcode算法入门与数组丨打卡笔记 这篇博客是一个 入门型 的文章&#xff0c;主要是自己学习的一个记录。 内容会参…

SSM SpringBoot vue快递柜管理系统

SSM SpringBoot vue快递柜管理系统 系统功能 登录 注册 个人中心 快递员管理 用户信息管理 用户寄件管理 配送信息管理 寄存信息管理 开发环境和技术 开发语言&#xff1a;Java 使用框架: SSM(Spring SpringMVC Mybaits)或SpringBoot 前端: vue 数据库&#xff1a;Mys…

【GAMES202】Real-Time Ray Tracing 1—实时光线追踪1

一、前言 这篇我们开始新的话题—Real-Time Ray Tracing简称RTRT&#xff0c;也就是实时光线追踪&#xff0c;关于光线追踪&#xff0c;我们已经不止一次提到过它的优点&#xff0c;无论是软阴影还是全局光照&#xff0c;光线追踪都很容易做&#xff0c;唯一的缺点就是速度太慢…

超简单免费转换ape到flac

1. 安装最新版的ffmpeg 2. 安装cywin环境 3. 设置path到ffmpeg export PATH$PATH:"PATH/TO/FFMPEG/BIN" 4.到ape所在的目录&#xff0c;执行以下命令 find . -iname "*.ape" | while read line; do fb${line::-4}; fn"$fb.flac";echo ffm…

快速加入Health Kit,一文了解审核流程

HUAWEI Health Kit是为华为生态应用打造的基于华为帐号和用户授权的运动健康数据开放平台。 在获取用户授权后&#xff0c;开发者可以使用Health Kit提供的开放能力获取运动健康数据&#xff0c;基于多种类型数据构建运动健康领域应用与服务&#xff0c;为用户打造丰富、便捷、…

第14篇ESP32 idf wifi联网_WiFi STA 模式(连接到WIFI)LCD ST7920液晶屏显示

第1篇:Arduino与ESP32开发板的安装方法 第2篇:ESP32 helloword第一个程序示范点亮板载LED 第3篇:vscode搭建esp32 arduino开发环境 第4篇:vscodeplatformio搭建esp32 arduino开发环境 ​​​​​​第5篇:doit_esp32_devkit_v1使用pmw呼吸灯实验 第6篇:ESP32连接无源喇叭播…