网站首页 > 教程文章 正文
之前遇到过一位后端大哥自告奋勇,参与前端一个vue3项目的功能实现。当功能完成时大哥体现出他对vue3框架正确的认知,但轮到我看代码时,满屏的var让我不禁汗颜。
“声明变量不就是用var吗?“
“let和var不都是声明变量,你直接把var替换成let不就行了......”
相信不只是这位大哥,也有不少同学在学习ES6的知识后,也是简单认为let和const就只是代替了var的新用法。
变量提升
ES6之前我们只学了var关键字进行变量的声明,同时我们可以复习下变量提升的概念。
var声明的变量具有变量提升的特性,在javascript的创建阶段过程中,会对声明的变量与函数进行收集,提升到作用域的顶部。
其中有两个细节:
1.只有声明被提升(变量会初始化为undefined)
2.当变量名和函数名冲突时,函数会被优先提升
具体看下变量提升的效果:
console.log(num) // undefined
console.log(fun) // function fun(){...}
var num = 1
var fun = 2
function fun(){
// ...
}
console.log(num) // 1
console.log(fun) // 2
一、let、const
1.let和const的具体使用
ES6新增了let和const关键字:
- let用于声明变量,用法与var类似
- const用于声明常量:
- 与变量不同,常量是一个恒定的值,只读,不可修改
- 常量在定义时必须进行初始化赋值
- 相同特性:
- 在相同作用域内,无法对同一个变量/常量进行重复声明
- 存在暂时性死区
- 会形成块级作用域
- 不会在全局声明时(在最顶层作用域)创建window对象的属性
我们通过代码,观察以上的特性:
- const声明的常量无法被修改。
let varData = 'variable';
const constData = 'constant';
varData = 1;
constData = true // Uncaught TypeError: Assignment to constant variable.
- const声明时必须进行初始化(let可以不进行初始化赋值)。
let varData;
const constData; // Uncaught SyntaxError: Missing initializer in const declaration
- const声明的注意点:
const只是限制变量绑定的值,不会限制引用数据类型内部的变动。
const a = {
num : 1
}
a.num = 2 // 对象的属性仍然可以被改动,不被影响
a = 2 // 报错
- 同一作用域内,无法对同一个变量/常量进行重复声明。
let varData;
let varData = true; // Uncaught SyntaxError: Identifier 'varData' has already been declared
const constData = 1;
const constData = 2 //Uncaught SyntaxError: Identifier 'constData' has already been declared
var varData
let varData = 2 //Uncaught SyntaxError: Identifier 'varData' has already been declared
- 重复声明的注意点:
在switch语句中,因为let或const声明会形成块级作用域,也会导致重复声明。switch (key) {
case 1:
let a = 1
break;
case 2:
let a = 2 //Identifier 'a' has already been declared
break;
}
2.暂时性死区
暂时性死区:Temporal dead zone——TDZ
先看一段代码,方便我们对暂时性死区的理解:
console.log(a) // undefined
var a = 1
在js阶段时,我们学过预解析,var声明的变量会在初始化赋值前,进行变量提升(hoisting),在进行代码的执行阶段时,a变量已经存在,且值为undefined
这种逻辑其实有些奇怪,我们对变量a进行声明和初始化赋值,是为了后面的逻辑和功能,但在进行初始化赋值前,变量a就已经可以进行访问,并且有值。
ES6中为了纠正这种现象,改变语法行为:对let和const声明的变量/常量,一定要在声明后使用,否则报错
console.log(a) // Uncaught ReferenceError: Cannot access 'a' before initialization
let a = 1
在'暂时性死区'的概念中,let和const声明的变量/常量都规避了变量提升(hoisting)特性带来的怪异逻辑,让前端程序员在编写代码时,以更严谨的角度去进行编程,防止多余的误操作。
3.块级作用域
在ES6之前,只有全局作用域和函数作用域,在ES6中,新增了块级作用域
块级作用域由一对大括号界定,在大括号内使用let和const进行声明,才会形成块级作用域
{
let a = 1;
console.log(a) // 1
}
console.log(a) // a is not defined
让我们来看一下,块级作用域存在前后的对比:
- if执行语句中,var声明的变量直接作用于if语句所在的作用域内。
if(false){
var a = 1
}
console.log(a) // undefined
- 可以通过下面这个例子,更直观地观察:没有块级作用域带来的场景误读。
var title = 1
function fun(){
if(title == undefined){
var title = 10
}
console.log(title) // 10
}
fun()fun函数中,使用var声明的title变量因变量提升(hoisting)特性,在执行前被提升到函数作用域顶部,且初始值为undefined,当进入执行阶段时,if判断为true,进入if执行语句,进行title的赋值操作。
这也是很多初学者一开始就会产生的疑问:
A:‘我明明是if判断成功,我才声明这个变量并初始化,那在这一步操作之前,title不应该是沿着作用域链去寻找全局作用域中的title吗?‘。
B:‘变量提升(hoisting)的特性’。
A:’那我肯定是要符合条件,才进入if执行语句,里面的代码才会执行,title这个变量才去初始化和赋值。现在变量提升不就导致了判断条件受到影响?'。
B:‘变量提升(hoisting)的特性’。
A: '......(按住自己的拳头)'。
这个对话可能有些绕,我们可以看图来解读这个同学的疑惑:
- 拥有块级作用域后,这段代码的解读就不会出现误读的情景。
var title = 1
function fun(){
if(title == undefined){
let title = 10
}
console.log(title) // 1
}
fun()
- for循环中var声明的计数变量直接作用于for语句所在的作用域内。
function fun(){
for (var i = 0; i < 10; i++){
// ...
}
console.log(i); // 10
}
- 拥有块级作用域后,可以避免用来计数的循环变量泄露。
function fun(){
for (let i = 0; i < 10; i++){
// ...
}
console.log(i); // i is not defined
}
- 异步代码执行过程中,需要通过IIFE实现closure(闭包),达到打印目标。
function fun(){
for (var i = 0; i < 10; i++){
;(function(i){
setTimeout(()=>{
console.log(i); // 0 1 2 3 ...
})
})(i)
}
}
- 拥有块级作用域后,不需要再通过closure(闭包)主动进行词法环境收集。
function fun(){
for (let i = 0; i < 10; i++){
setTimeout(()=>{
console.log(i); // 0 1 2 3 ...
})
}
}
总结
总结和了解var、let和const的特点后,我们才能明白"直接将var替换成let"这种做法携带的安全隐患有多大。
分析var和let/const的区别,必然要理清变量提升(Hoisting)、暂时性死区(TDZ)和块级作用域(block)这几个概念分别产生的效果。
let、const也是为了解决使用var时形成怪异逻辑的问题。通过规范的语法行为,统一代码的正确解读,减少代码在编写及运行时的误操作,提高代码的安全性和可读性。
猜你喜欢
- 2025-01-14 js中const,var,let三种区别
- 2025-01-14 var、let、const定义JavaScript变量常量
- 2025-01-14 JavaScript中let、const和var的使用介绍
- 2025-01-14 javascript中const/let/var的用法区别及使用场景
- 2025-01-14 Vue进阶(四十二):var、let、const三者的区别
- 2025-01-14 JS:定义变量的var、let有何操作?(360°无死角)
- 2025-01-14 JavaScript 中 var, let, const 的区别?
- 2025-01-14 JavaScript基础06——let和var两个关键字有啥不同
- 2025-01-14 JavaScript let 与var 区别及var弊端
- 05-11阿里开源MySQL中间件Canal快速入门
- 05-11MyBatis插件开发实战:手写一个分页插件
- 05-11Flask数据库——SQLAlchemy
- 05-11MySQL 到 Hazelcast Cloud 实时数据同步实操分享
- 05-11sqlmap 详解
- 05-11一篇文章让你学会Elasticsearch中的查询
- 05-11Mysql性能优化这5点你知道吗?简单却容易被初学者忽略!
- 05-11Spring Boot 实现 MySQL 读写分离技术
- 最近发表
- 标签列表
-
- location.href (44)
- document.ready (36)
- git checkout -b (34)
- 跃点数 (35)
- 阿里云镜像地址 (33)
- qt qmessagebox (36)
- md5 sha1 (32)
- mybatis plus page (35)
- semaphore 使用详解 (32)
- update from 语句 (32)
- vue @scroll (38)
- 堆栈区别 (33)
- 在线子域名爆破 (32)
- 什么是容器 (33)
- sha1 md5 (33)
- navicat导出数据 (34)
- 阿里云acp考试 (33)
- 阿里云 nacos (34)
- redhat官网下载镜像 (36)
- srs服务器 (33)
- pico开发者 (33)
- https的端口号 (34)
- vscode更改主题 (35)
- 阿里云资源池 (34)
- os.path.join (33)