var、let、const的区别和推荐使用

简介: var、let、const的区别和推荐使用

一、使用 var 的函数作用域声明---变量提升机制

在使用 var 声明变量时,变量会被自动添加到最接近的上下文。在函数中:最接近的上下文是函数的局部上下文;在 with 语句中,最接近的上下文也是函数上下文;如果变量未经声明就被初始化,那么它就会自动被添加到全局上下文。

function add(num1, num2){
    var num = num1 + num2
    return sum
}
let result = add(10, 20); // 30
console.log(sum) //报错,sum在这里不是有效变量

这里函数 add 定义了一个局部变量 sum,保存加法操作的结果。但是变量 sum 在函数外部是访问不到的,如果省略了上面例子中的关键字 var ,那么 sum 在 add 被调用后就变成可以访问的了

function add(num1, num2){
    num = num1 + num2
    return sum
}
let result = add(10, 20); // 30
console.log(sum)         //  30

这一次,变量 sum 变量并没有使用 var 声明,在调用 add() 之后 ,sum 被添加到了 全局上下文,在函数退出之后依然存在,从而在后面可以访问到。


总结:


var 声明会被拿到函数 或 全局作用域的顶部,位于作用域中 所有代码之前。这个现象叫作“提升”(hoisting)。提升让同一作用域的代码不必考虑变量是否已经声明就可以直接使用。可是在实践中,提升也会导致 合法却奇怪的现象。


未经声明而初始化变量时 JavaScript 编程中 一个非常常见的错误,会导致很多问题。为此,在初始化变量之前,一定要先声明变量。在严格模式下,未经声明就初始化的变量会报错

二、使用 let 的块级作用域声明---暂时性死区( temporal dead zone )

ES6新增的 let 关键字跟 var 很相似,但它的作用域是块级的,这也是 JavaScript 中的新概念。块级作用域是由最近的一对 {  } 界定,比如:if块、while块、function块、甚至连单独的块也是 let 声明变量的作用域。

var a;
var a; // 不会报错,后声明都变量会覆盖先声明的变量
{
    let b;
    let b;
}  // SyntaxError : 标识符 b 已经声明过了

看上面示例:let 与 var 的另一个不同之处是在同一作用域内不能声明两次。重复的 var 声明会被忽略,而重复的 let 声明 会抛出 SyntaxError

for(var i = 0; i < 10; ++i){   }
console.log(i); // 10
for(let j = 0; j < 10; ++j){   }
console.log(j); // ReferenceError : j 没有定义

来看上面两个例子:let 的行为非常适合再循环中声明迭代变量。使用 var 声明的迭代变量 会泄露到循环外部,这种情况应该避免。


总结:


严格来讲,let 在 JavaScript 运行时也会被 提升,单由于“暂时性死区”(temporal dead zone) 的缘故,实际上不能再声明之前使用 let 变量。因此,从写 JavaScript 代码的角度来说,let 的提升和 var 是不一样的。


暂时性死区:用一句话来概括就是 JavaScript引擎 一进入作用域创建变量,到变量开始可以被访问之间的一段时间,就称之为 TDZ。

三、使用 const 的常量声明

const a;  // SyntaxError : 常量声明时没有初始化
const b = 3;
console.log(b);  // 3
b = 4; TypeError : 给常量赋值

除了 let ,ES6同时还增加了 const 关键字。使用 const 声明的变量必须同时初始化某个值,一经声明,在其声明周期都不能在重新赋予新值。const 除了要遵循以上规则,其他方面与 let 声明是一样的;

const o1 = {};
o1 = {};       // TypeError : 给常量赋值
const o2 = {};
o2.name = 'Barry';
console.log(o2.name); //  'Barry';
const o3 = Object.freeze({  });
o3.name = 'Barry';
console.log(o3.name);  // undefined

const 声明只应用到最顶级原语或对象。 换句话说,赋值为对象的 const 变量 不能再被重新赋值为其他引用值,但对象的键则不受限制;

如果想让整个对象都不能修改,可以使用 Object.freeze() , 这样再给属性赋值时虽然不会报错,但会静默失败;

四、let  const 更推荐那个?

开发实践表明,如果开发流程并不会因此而受很大影响,就应该尽可能地多使用 const 声明,除非确实需要一个将来会重新赋值的变量。这样可以从根本上保证提前发现重新赋值导致的bug。


相关文章
|
11月前
|
人工智能 算法 前端开发
我和通义灵码的一周年
通义灵码是阿里巴巴推出的一款AI插件,大小约5.8M,适用于IDEA开发环境。它通过@workspace和@terminal两大功能,显著提升代码开发效率和质量。@workspace帮助开发者快速理解项目结构,智能导航至关键代码;@terminal则提供命令行下的代码搜索与实时补全,加速开发流程。实际应用中,通义灵码大幅缩短了新项目熟悉时间,减少了试错成本,提升了代码的规范性和稳定性。
269 0
|
9月前
|
机器学习/深度学习 人工智能 算法
《人工智能:洞察材料微观与宏观性能关系的神奇之眼》
在材料科学领域,人工智能正以前所未有的力量精准模拟材料微观结构与宏观性能的复杂关系。通过深度学习算法,AI将微观结构图像转化为数字化特征,揭示出传统方法难以企及的非线性映射规律。海量数据作为基石,使模型能够预测新材料的宏观性能,大幅缩短研发周期并降低成本。这一前沿技术不仅推动了航空航天、电子芯片等领域的技术飞跃,还在半导体、生物医用材料等方面展现出巨大潜力,成为材料科学创新的核心驱动力,引领人类迈向更智能、可持续的未来。
215 5
|
11月前
|
JavaScript
【小白懂系列】Vue CLi脚手架创建第一个VUE项目
【小白懂系列】Vue CLi脚手架创建第一个VUE项目
167 2
|
消息中间件 监控 Shell
RocketMQ-初体验RocketMQ(03)_RocketMQ多机集群部署
RocketMQ-初体验RocketMQ(03)_RocketMQ多机集群部署
185 0
|
SQL 存储 分布式计算
Linux退出Hive命令
【8月更文挑战第14天】
212 1
|
前端开发 开发者
react class与hooks区别
react class与hooks区别
270 0
|
消息中间件 安全 大数据
Kafka多线程Consumer是实现高并发数据处理的有效手段之一
【9月更文挑战第2天】Kafka多线程Consumer是实现高并发数据处理的有效手段之一
948 5
|
JavaScript Java 测试技术
基于微信小程序的汽车维修管理系统的设计与实现(源码+lw+部署文档+讲解等)
基于微信小程序的汽车维修管理系统的设计与实现(源码+lw+部署文档+讲解等)
215 0
|
机器学习/深度学习
YOLOv5改进 | 注意力篇 | ACmix自注意力与卷积混合模型(提高FPS+检测效率)
YOLOv5改进 | 注意力篇 | ACmix自注意力与卷积混合模型(提高FPS+检测效率)
327 0
|
传感器 Ubuntu Java
ESP-IDF 蓝牙开发实战 — 传感器数据上传及手机控制开发板
ESP32-C3 蓝牙部分我们学习了GATT,本文博主手把手带领大家使用 ESP32-C3的蓝牙做一个简单的小应用。
2105 0
ESP-IDF 蓝牙开发实战 — 传感器数据上传及手机控制开发板