js中var、let、const之间的区别
作者:前端深情大男孩 发布时间:2024-04-23 09:11:29
一、什么是变量
在读这篇文章前,我们需要搞懂到底是什么变量,其实一句话就能概括:变量是一个可以保存任何数据类型值的命名占位符。
本篇文章将会介绍以下知识点:
什么是var、let、const
变量声明规则
变量提升
块作用域
暂时性死区
二、var关键字
2.1 初始化
初始化变量只需要在var
关键字后面跟变量名即可:
var a;
var b = 2;
上面这段代码声明了a和b两个变量,a变量只是单纯的声明,并没有赋值,js引擎遇到未赋值的变量时,会自动为其赋值一个值,这个值就是undefined
;变量b在声明的时候我们给它赋值了一个数字2
,所以当获取变量b的时候,会得到一个number类型的2。
说到number类型,这里就不得不提到一个概念:JavaScript中的变量属于松散类型,也就是变量的值可以变更为任何数据类型的值,但并不建议这么做,随意更改变量的数据类型会导致代码可读性降低。
// 翻译后是var a = undefined;
var a;
var b = 2;
b = '2'; // 不建议这么做
在代码开发过程中,有些场景需要创建多个变量,除了var a = 1; var b = 2;
这种写法,还可以使用,
进行更便利的创建多个变量:
// 使用逗号创建多个变量
var a = 1,
b = 2,
c = 3;
// 等同于
var a = 1;
var b = 2;
var c = 3;
2.2 var声明作用域
变量存在哪个作用域中是根据变量所声明的场景位置决定,有两种场景:全局、函数
。在全局作用域中声明var变量,该变量在任何地方都可以被访问到,而且还可以通过window.变量名
访问。如果在函数内部声明变量,那么这个变量就只属于这个函数自己的,外部访问就会报错,最后变量会在函数退出的时候被销毁。
// 声明全局变量
var a = 1;
// 访问全局变量
console.log(a); // 1
console.log(window.a); // 1
// 声明函数作用域内的变量
function fun () {
var b = 2; // 只属于fun函数的变量
console.log(b); // 2
};
fun(); // 2
console.log(b); // 报错:b is not defined(变量b未定义)
2.3 var的变量提升
变量提升其实就是在初始化的时候,var变量会提升到当前作用域最顶部,并且每一个变量的值都是默认undefined,当js引擎执行到变量赋值的代码后,变量的值才会是我们想要的那个值,根据这个理论,来看下面一段代码,思考一下代码执行的结果是什么:
var a = 1,
b = 2;
function fun (a) {
console.log(b);
var b = 6;
var b = 5;
console.log(a);
console.log(b);
};
console.log(b);
fun(4);
console.log(b);
上面这段代码其实并没有复杂的交互,只是多次的访问某些变量,会让人有点眼花,没关系,我们来一步一步的分解这些代码,得到最终的结果,看是否和你的结果一样:
全局作用域中出现了三个变量:
a、b、fun
(函数名也是一个变量)在函数执行前打印了全局作用域中的变量b,所以得到的是
2
调用函数并传入参数值,开始执行函数内部代码
此时函数内部变量a和b都提升到了函数作用域顶部,并且值都是undefined
变量a被赋值4
打印变量b,此时变量还没有被赋值,所以得到的是
undefined
变量b开始被赋值,但遇到了两个重名变量,最后一个变量会覆盖之前的所有重名变量
获取变量a,还记得吗?在执行参数的时候给变量a赋值了4,所以我们获得的也是
4
因为之前的变量b被后面的变量b覆盖了,所以现在获取变量b,获得的是
5
函数内部代码执行完毕,开始获取变量b的值
虽然函数内部也有b变量,但那是属于函数自己的,并且这个变量在函数执行完后被销毁了,所以我们只能获取到全局作用域下的变量b,内容是
2
所以最终结果是:2、undefined、4、5、2
。
全局变量
全局变量除了在最外层声明,其实还有另外一种声明方式,不过这种方式并不受推荐,所以了解就好:
var a = 1; // 正常的声明全局变量
function fun () {
b = 2; // 变量名前面没有写var,默认成为全局作用域
};
// 因为函数还没有执行,所以这块会报错
console.log(b); // b not defined
fun();
console.log(b); // 2
三、let声明
3.1 块级作用域
相比于var变量,let显得更加精致,因为它有自己的声明准则,其中最大的区别就是let声明的范围是块级作用域,那么什么是块级作用域呢,其实很好理解:{}
符号中的区域被称为块级作用域,需要注意的是这个区域对var并没有影响。
块级作用域和函数作用域相似,控制着内部变量的读取权限
{ // 块级作用域
let a1 = 2;
}
console.log(a1); // 报错:a1 is not defined
3.2 暂时性死区
在let创建之前的瞬间被称为暂时性死区
,听起来很高级,其实就是在暂时性死区阶段访问不到let变量的意思,因为let变量没有变量提升这一说;let还有一个特点就是不能被重复声明,也就是说let变量不会像var变量一样可以声明多个重名变量,在let变量这会报错的。
{
console.log(b); // 因为没有变量提升,所以在声明前访问不到该变量,报错:annot access 'b' before initialization
let b = 1;
}
let a = 1;
let a = 2; // 重名变量会报错:caught SyntaxError: Identifier 'a' has already been declared
let的全局作用域
虽然前面说let声明的范围是块级作用域,但如果在最外层全局作用域里声明let变量,也会被认为是合法的全局变量,与var变量不同的是let全局作用域不能通过window.变量名
访问。
for循环中的let和var
for循环过程中会不断产生新的块级作用域,这个时候var和let变量值迭代更新就有了不同的变化:
let arr = [1, 2, 3, 4, 5];
for (let i = 0; i < arr.length; i++) {};
console.log(i); // 报错:i is not defined
for (var i = 0; i < arr.length; i++) {};
console.log(i); // 5
上面代码中第一个循环内,使用let创建了一个变量,当我们在循环体外访问该变量时竟然报错了!这是因为循环体使用了{}
,所以形成了块级作用域,此时在块作用域外访问let变量肯定会报错。当我们访问var变量的时候为什么没有报错呢?那是因为var变量不受块级作用域影响,它成为了全局作用域。
四、const声明
const声明被称为常量,为了更好理解,下文还是用变量进行介绍
const和let非常相似:不能声明重名变量、存在暂时性死区、没有变量提升、有块级作用域限制
。这些都是非常nice的规则,在此基础上,const还增加了两个规则:1、声明时必须赋值;2、值不可修改;
声明时必须赋值这个很好理解,就是在创建的时候必须给这个变量一个初始值。我们详细说一下值不可修改
这一点:
const a = '2';
a = 2; // 报错a变量已经声明,不能重复创建:entifier 'a' has already been declared
上面代码首先我们创建了const变量并为其赋值字符串类型的'2',在第二行代码实际上是想把数字类型的2赋值给刚刚创建的const变量中,这时候确保错了,由此可见const变量适合用在值不会变的场景。还有一种情况就是给const变量赋值数组和对象类型的值,因为这两个数据类型属于引用类型,所以只要在引用地址值不变的情况下,更改、新增、删除对象或数组中的元素是不会报错的。
var | let | const | |
---|---|---|---|
变量提升 | √ | × | × |
重复声明相同名称变量 | √ | × | × |
是否可以更改变量值 | √ | √ | × |
函数作用域 | √ | × | × |
块作用域 | × | √ | √ |
来源:https://juejin.cn/post/7233664581167317049


猜你喜欢
- 前言本文主要给大家介绍了关于python中MethodType方法的相关内容,分享出来供大家参考学习,话不多说,来一起看看详细的介绍吧示例代
- 大家好,我是煎蛋哥!上篇文章聊到了 Python 实现大 * 票自由的完整流程如何使用 Python 实现彩票自由(大乐透)和体彩大乐透类似
- 什么是CPU/PSUOracle CPU的全称是Critical Patch Update, Oracle对于其产品每个季度发行一次安全补丁
- magpierss中就用到了snoopy,这让我有点兴趣去研究下这个咚咚。再SF上,找到了这个源代码。居然就是一个类,但不要笑看哦,功能可是
- 最近在学习python爬虫,看到网上有很多关于模拟豆瓣登录的例子,随意找了一个试了下,发现不能运行,对比了一下代码和豆瓣网站,发现原来是豆瓣
- 一、如何理解本条内容:一个“简单”和“复杂”的例子在我和开发人员沟通一个项目需求的时候,他们频频慨叹Mockup的设计所考虑情况之细致,很多
- 我们经常在B站上看到一些字符鬼畜视频,主要就是将一个视频转换成字符的样子展现出来。看起来是非常高端,但是实际实现起来确是非常简单,我们只需要
- mysql.sock到底存储了什么东西?mysql.sock作为mysql的套接字一般用于本地连接数据库,在速度上优于TCP/IP连接。一般
- python 地图经纬度转换、纠偏的代码如下所示:# -*- coding: utf-8 -*-import jsonimport urll
- 使用python中的pandas,xlrd,openpyxl库完成合并excel中指定sheet的操作# -*- coding: UTF-8
- meta是用来在HTML文档中模拟HTTP协议的响应头报文。meta 标签用于网页的<head>与</head&
- 本文为大家分享了python实现俄罗斯方块游戏的具体代码,供大家参考,具体内容如下Github:Tetris代码:# -*- coding:
- 1.前言数据展示,即数据可视化,是数据分析的第五个步骤,大部分人对图形敏感度高于数字,好的数据展示方式能让人快速发现问题或规律,找到数据背后
- 今天我们用python和pygame实现一个乒乓球的小游戏,或者叫弹珠球游戏。笑脸乒乓球游戏功能介绍乒乓球游戏功能如下:乒乓球从屏幕上方落下
- 最近经常有收到MySQL实例类似内存不足的报警信息,登陆到服务器上一看发现MySQL 吃掉了99%的内存,God !有时候没有及时处理,内核
- 引言最近python语言大火,除了在科学计算领域python有用武之地之外,在游戏、后台等方面,python也大放异彩,本篇博文将按照正规的
- 本文实例讲述了python版本的读写锁操作方法。分享给大家供大家参考,具体如下:最近要用到读写锁的机制,但是python2.7的自带库里居然
- 1.主要功能如下:1.classification分类2.Regression回归3.Clustering聚类4.Dimensionalit
- 什么是 Socket?Socket又称"套接字",应用程序通常通过"套接字"向网络发出请求或者应答网
- 标题pycharm专业版(python License Activate)python运行的环境大多数人用的比较多的是pycharm,但是很