JS变量声明var、let、const详解

JavaScript 中的变量是松散类型的,可以保存任何类型数据,变量只不过是一个名称。JavaScript 中,可以声明变量的关键字有var、let和const。

一、var

使用var定义变量,可以保存任何类型的值。若不初始化变量,变量会保存undefined。

1.1函数级作用域

使用var定义的变量会成为包含它的函数的局部变量。

function func() {var a = 'hi'; // 局部变量
}
func();
console.log(a); // ReferenceError: a is not defined

变量a在函数内部使用var定义,调用函数func,会创建这个变量并给它赋值。函数执行结束后,变量就会被销毁,所以上述代码最后一行会报错,显示变量a未定义。

若在函数内部,不使用var操作符,直接给变量a赋值,那么a就成为了全局变量,可以在函数外部访问到。在浏览器环境下,a成为window对象的属性。

function func() {a = 'hi'; // 全局
}
func();
console.log(a); // hi
console.log(window.a); // hi
console.log(window.a === a); // true

1.2 变量提升

使用var声明变量,会自动提升到函数作用域顶部,如下代码:

function func() {console.log(a);var a = 1;
}
func(); // undefined

代码没有报错,输出了undefined,这是因为变量的声明被提升到了函数作用域顶部,等价于如下代码:

function func() {var a;console.log(a);a = 1;
}
func(); // undefined

1.3 重复声明

另外,使用var重复声明同一个变量也可以:

function func() {var a = 1;var a = 2;var a = 3;console.log(a);
}
func(); // 3

1.4 全局变量挂载到 window

浏览器环境中,全局作用域下,使用var声明的变量,会挂载到window对象上。

var a = 1;
console.log(window.a === a); // true

一道面试题:

console.log("1":a,b);
var a = 12,b="34";
function foo(){console.log("2":a,b);var a=b=12;console.log("3":a,b);
}
foo()
console.log("4":a,b);

答案:
1 : undefined,undefined //变量已经声明但是未赋值,这里为什么会说变量已经声明了,是因为js编译时会把所有的变量声明到最前面,其次是函数的声明
2: undefined, ‘34’ //因为下面的var a=又把a声明了一次所以,a就又是undefined,注意这里b并没有被声明,如果把var a=b=12改成,var a=12,b=12那么答案就是undefined,undefined
3: 12,12 //a,b均已声明并赋值
4: 12,12 //a,b均已声明并赋值,但是这里要和上一个区分,b=12是因为在函数中重新赋值了。就如第二条所说,如果把var a=b=12改成,var a=12,b=12那么答案就是12,“34”并且这个12是第二行赋值的。

二、let

let也可以声明变量,但和var操作符有很大的区别。

2.1 块级作用域

以下代码会报错,因为let声明的作用域,具有块级作用域,即被{}包裹的部分。

if (true) {let a = 10;
}
console.log(a); // a is not defined

2.2 不可重复声明

以下代码,执行到let a = 2就会报错,因为变量a在当前块级作用域中已经被声明过了,不能重复声明。

if (true) {let a = 1;let a = 2; // SyntaxError: Identifier 'a' has already been declaredlet a = 3;
}

另外,如果混用var和let声明变量,也是不允许的,下面的代码都会报错:

let a;
var a; // 报错
var a;
let a; // 报错

2.3 不存在变量提升(暂时性锁区)

使用let声明的变量,不能在声明之前访问它。

if (true) {console.log(a); // ReferenceError: Cannot access 'a' before initializationlet a = 1;
}

实际上,JavaScript 也会注意出现在块后面的let声明,只不过在此之前不能以任何方式来引用未声明的变量。在let声明之前的执行瞬间被称为暂时性死区。

2.4 全局变量不会挂载到 window

和var不同,即使在全局作用域下,使用let声明的变量也不会挂载到window对象。

var a = 1;
let b = 2;
console.log(window.a === a); // true
console.log(window.b === b); // false

2.5 不依赖条件声明

if (typeof name === 'undefined') {let name;
}
// name 被限制在 if {} 块的作用域内
name = 'Matt'; // 全局赋值try {console.log(age); // 如果 age 没有声明过,则会报错
} catch (error) {let age;
}
// age 被限制在 catch {}块的作用域内
age = 26; // 全局赋值

三、 const

const的特点与let基本一致,但const有一些自己的特点。

3.1 声明变量时必须同时初始化

以下声明报错,因为声明的同时没有初始化变量。

const a; // Missing initializer in const declaration

3.2 不能修改声明后的变量

使用const定义了一个变量后,不能再更改它的值:

const a = 1;
a = 2; // TypeError: Assignment to constant variable

这里有一个误区,实际上,使用const声明的变量,不能修改的是内存地址!!

具体规则如下:

  • 当const定义的常量为基本数据类型时,不能被修改。
  • 当const定义的常量为引用数据类型时,可以通过其属性进行数据修改。

基本数据类型的值就保存在内存地址中,所以const定义的基础数据类型不可被改变。 而引用数据类型指向的内存地址只是一个指针,通过指针来指向实际数据,也就是说,不可被改变的是指针,而不是数据,所以const定义的引用数据类型的常量可以通过属性来修改其数据。

例如,使用const定义了一个数组,虽然不能更改数据类型,但可以通过push等方法,修改这个数组中的数据。

const arr = [];
arr.push(1, 2, 3);
console.log(arr); // [ 1, 2, 3 ]

五、总结及最佳实践

varletconst
函数级作用域块级作用域块级作用域
重复声明不可重复声明不可重复声明
变量提升不存在变量提升不存在变量提升
值可更改值可更改值不可更改
全局变量挂载到window全局变量不会挂载到window全局变量不会挂载到window

通常,写 JavaScript 代码时,遵循以下原则:

  • 不使用var
  • const优先,let次之

一道面试题:

for (var i = 1; i <= 5; i++) {setTimeout(function () {console.log(i);}, 0);
}

答案:6 6 6 6 6

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

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

相关文章

Redis基础操作与持久化

目录 引言 一、Reids工具与数据类型 &#xff08;一&#xff09;Reids工具 &#xff08;二&#xff09;Redis数据类型 1.String&#xff08;字符串&#xff09; 2.Hash&#xff08;哈希&#xff09; 3.List&#xff08;列表&#xff09; 4.Set&#xff08;集合&#xff…

实践笔记-linux内核版本升级(centos7)

linux内核版本升级 1.查看当前内核版本信息2.采用yum方式进行版本升级2.1导入仓库源2.2选择 ML 或 LT 版本安装2.3设置内核启动 3.删除旧版本内核 1.查看当前内核版本信息 #查看操作系统版本 cat /etc/redhat-release #查看系统内核 uname -r2.采用yum方式进行版本升级 2.1导…

白色磨砂质感html5页源码

白色磨砂质感html5页源码&#xff0c;简约的基础上加上了团队成员&#xff0c;自动打字特效音乐播放器存活时间 源码下载 https://www.qqmu.com/2980.html

LCR测试仪的开路与短路

开路清零 上档 开路 进入开路清零菜单 执行以下步骤进行开路清零&#xff1a; 仪器处于测试状态下&#xff0c;按上档 键&#xff0c;屏幕左上角“SHIFT”点亮。按下开路 键 选择清零功能&#xff0c;LCD 显示信息如图所示通过【▲】或【▼】来选择执行“SPOT”或“SWEEP”…

即将上-UE独立程序高级开发-自动化系统

我们即将带来自动化高级开发内容 自动化服务器 自动化蓝图脚本编辑 自动化游戏测试 自动化镜像 自动化压缩美术流程 即将上架-UE独立程序高级开发-自动化系统_哔哩哔哩_bilibili

vscode的源码插件GitHub Repositories

打铁还需自身硬&#xff0c;需要不断提升自我&#xff0c;提升自我的一种方式就是看源码&#xff0c;站在更高的维度去理解底层原理&#xff0c;以便以后更好的开发和解决问题&#xff0c;由于源码一个动不动就是几个G甚至十几个G&#xff0c;如果一个个源码下载下来&#xff0…

数字图像处理项目——基于BCNN和迁移学习的鸟类图像细粒度分类(论文/代码)

完整的论文代码见文章末尾 以下为核心内容 摘要 本文采用了ResNet50、VGG19、InceptionV3和Xception等四种不同的深度神经网络模型&#xff0c;并应用于鸟类图像的细粒度分类问题中&#xff0c;以探究其在该任务上的性能表现。 其中&#xff0c;本文使用了BCNN&#xff08;B…

查分约束学习

问题模型&#xff1a; 有n个变量&#xff1a;&#xff0c;有m个约束条件 令差分数组&#xff0c;可以知道如果x1x2<q&#xff0c;那么与j和i-1有关联 由画图可知&#xff0c;如果有在i-1至j建立的有向图中跑最短路&#xff0c;那么dis[n]即为最小的约束变量 另外&#x…

Chrome浏览器如何跟踪新开标签的网络请求?

在测试一个东西的时候&#xff0c;它虽然是a链接&#xff0c;但是&#xff0c;是由前端在js里写跳转的。我又必须要知道它的跳转链接&#xff0c;只能用截屏的方式来捕捉浏览器的地址栏链接 打开浏览器控制台(F12)点击红色箭头打钩为弹出式窗口自动打开DevTools 英文版调试参…

华大单片机新建工程步骤

1.新建文件夹&#xff0c;比如00_LED 2.拷贝 hc32f460_ddl_Rev2.2.0\driver 到 00_LED 3.拷贝 hc32f460_ddl_Rev2.2.0\mcu\common 到 00_LED 4.拷贝 hc32f460_ddl_Rev2.2.0\example\ev_hc32f460_lqfp100_v2\gpio\gpio_output\source 到 00_LED 5.拷贝 hc32f460_ddl_Rev2.2.…

【数据结构】线性表部分习题2(顺序表与链表)

数据结构&#xff08;线性表部分2&#xff09; 数据结构习题持续更新中&#xff01;&#xff01;&#xff01; 目录 一、单选题二、简答题1. 顺序表就地逆置2. 循环单项链表的就地逆置 作业习题笔记&#xff1a; 该部分是线性表部分习题的补充、更多习题见: 数据结构&#xf…

933.最近的请求次数

题目&#xff1a;写一个 RecentCounter 类来计算特定时间范围内最近的请求。 请你实现 RecentCounter 类&#xff1a; RecentCounter() 初始化计数器&#xff0c;请求数为 0 。int ping(int t) 在时间 t 添加一个新请求&#xff0c;其中 t 表示以毫秒为单位的某个时间&#x…

HarmonyOS 开发-使用SideBarContainer侧边栏淡入淡出动效实现案例

介绍 在2in1或平板上&#xff0c;群聊侧边栏是一种较为常用的功能&#xff0c;虽然HarmonyOS已经具备了基本的动效&#xff0c;但是部分情况下开发者可能有定制侧边栏动效的需求&#xff0c;本例主要介绍了如何基于显式动画实现侧边栏的淡入淡出动效。 效果图预览 使用说明&a…

​泛微文书定人事档案一体化管理,覆盖人事管理全过程,人事档案全量归档

人事档案是个人身份、学历、资历等方面的证据&#xff0c;与个人工资待遇、社会劳动保障、组织关系紧密挂钩&#xff0c;具有法律效力。应注重收集和鉴别、整理工作&#xff0c;提升人事档案利用率。 企业应依据国家有关人事档案管理规定&#xff0c;制定企业人事档案管理办法&…

mysql性能索引调优易混点总结

文章目录 一、 前言二、explain相关三、索引优化相关联合索引索引下推排序和分组相关优化分页优化表关联优化嵌套循环连接 Nested-Loop Join(NLJ) 算法in和exsits优化 一、 前言 近几年看了很多和mysql相关的书&#xff0c;文章或视频&#xff0c;但仍然有一些点&#xff0c;看…

【吊打面试官系列】Java高并发篇 - 什么是线程组,为什么在 Java 中不推荐使用?

大家好&#xff0c;我是锋哥。今天分享关于 【什么是线程组&#xff0c;为什么在 Java 中不推荐使用&#xff1f;】面试题&#xff0c;希望对大家有帮助&#xff1b; 什么是线程组&#xff0c;为什么在 Java 中不推荐使用&#xff1f; ThreadGroup 类&#xff0c;可以把线程归属…

# 计算机视觉入门

## 概述 计算机视觉&#xff08;Computer Vision&#xff09;是人工智能的重要分支领域&#xff0c;它关注于如何使计算机“看”懂图像或视频内容&#xff0c;并从中提取有用信息&#xff0c;对视觉数据进行处理和理解。随着深度学习技术的兴起&#xff0c;计算机视觉领域取得…

排序+去重+二分,LeetCode 2009. 使数组连续的最少操作数

目录 一、题目 1、题目描述 2、接口描述 python3 cpp 3、原题链接 二、解题报告 1、思路分析 2、复杂度 3、代码详解 python3 cpp 一、题目 1、题目描述 给你一个整数数组 nums 。每一次操作中&#xff0c;你可以将 nums 中 任意 一个元素替换成 任意 整数。 如果 …

领鸡蛋游戏养鸡游戏淘宝客源码广告联盟

用户中心 用户信息&#xff1a;显示用户名、头像、鸡蛋数量、足迹等基本信息。我的足迹&#xff1a;展示用户的饲料获取记录明细&#xff0c;包括来源、数量和时间。我的好友&#xff1a;展示邀请的好友列表&#xff0c;支持好友间互动&#xff0c;如串门、偷取/赠送饲料&#…

wait 和 notify

由于线程之间是抢占式执行的, 因此线程之间执行的先后顺序难以预知。但是实际开发中有时候我们可以通过一些 api 让线程主动阻塞&#xff0c;从而控制多个线程之间的执行先后顺序. 完成这些操作就需要用到 wait&#xff0c;notify / notifyAll 注意: wait, notify, notifyAll…