0


【前端大忌】不要小看 let 和 const,这里面也博大精深

引言:最近,“const定义的对象属性是否可以改变?” 这道面试题频频出现。这一问题让我们意识到,

let

const

不仅仅是简单的变量声明方式,其中的知识点和应用场景也值得我们深入探讨。

WX20231120-135736@2x.png

在这篇文章中,我们将全面解析

let

const

的不同应用场景、堆栈和作用域详解、优缺点对比、技巧应用等。希望通过本文,你能对这两个关键字有更深入的理解,并能够在实际开发中灵活运用它们。

----借助目录阅读,效果更好。

基础概念与用法

在ES6(ECMAScript 2015)中,引入了

let

const

来替代传统的

var

进行变量声明。这两个关键字具有块级作用域,并且避免了

var

声明带来的许多问题。

  • let:用于声明可变的变量。
  • const:用于声明不可变的变量,但要注意的是,这里的“不变”是指变量绑定的值的引用不变,而不是值本身不变。
// 使用 let 声明变量let a =10;
a =20;// 允许重新赋值// 使用 const 声明变量const b =10;// b = 20; // 不允许重新赋值,会报错// const 声明对象const obj ={key:'value'};
obj.key ='newValue';// 允许修改对象属性
console.log(obj.key);// 输出 'newValue'

不同应用场景的深入分析

let

适用于需要在代码块内部重复赋值的变量声明,例如循环计数器、临时变量等。如下,

let

确保了

i

的作用域仅限于循环内部,避免了

var

可能导致的全局变量污染问题。

// 循环中的应用for(let i =0; i <10; i++){
  console.log(i);}// 条件语句中的应用let flag =true;if(flag){let message ='Hello, world!';
  console.log(message);// 输出 'Hello, world!'}// console.log(message); // 报错,message 不在作用域内
const

适用于声明那些在初始化后不会再被重新赋值的变量,例如常量、函数和对象。

// 1. 声明常量constPI=3.14159;// PI = 3.14; // 报错,不允许重新赋值// 2. 声明函数constgreet=function(){
  console.log('Hello, world!');}greet();// 3. 声明对象const user ={name:'Alice',age:25};
user.age =26;// 允许修改对象属性
console.log(user.age);// 输出 26

我们接着再从堆栈和作用域方面,深入分析下。。

faf2b2119313b07e299d9d7405ff132897dd8c5a.webp

堆栈和作用域详解

在JavaScript中,变量的声明和使用不仅仅是简单的赋值和调用,而是与内存管理、作用域链以及执行上下文等多个复杂机制密切相关。为了更好地理解

let

const

的工作原理,我们需要深入了解堆栈内存管理、作用域和变量提升以及暂时性死区(TDZ)的概念。

堆栈内存管理

JavaScript 中的变量储存在堆(Heap)和栈(Stack)中。基本类型(例如数字和布尔值)存储在栈中,而引用类型(例如对象和数组)存储在堆中。

image.png

  • :用于存储对象(Object)和大块的数据。
  • :用于存储基本数据类型(如字符串、数字等)和执行上下文(Execution Context)。
const x =10;// 基本类型,存储在栈中const y ={value:20};// 引用类型,y存储在栈中,实际对象存储在堆中

在 JavaScript 中,每当调用函数时,都会创建一个新的执行上下文并被压入栈顶。当函数执行完毕时,执行上下文从栈顶弹出,释放其所占用的内存空间。让我们通过一个示例来理解这一过程:

functionfoo(){let a =20;const b =30;
  console.log(a + b);}foo();

在上述代码中,当调用

foo

函数时:

  1. JavaScript 引擎创建一个新的执行上下文,其中包含 foo 函数的局部变量 ab
  2. 该执行上下文被压入栈中。
  3. 函数执行完毕后,执行上下文从栈中弹出,内存被释放。

这个过程确保了变量在其作用域范围内可访问,并在函数执行完毕后释放内存,避免内存泄漏。

作用域

作用域决定了变量的可访问性。在 JavaScript 中,作用域有三种类型:全局作用域、函数作用域和块级作用域。

  1. 全局作用域:在代码任何地方都可以访问的变量被称为全局变量。
  2. 函数作用域:使用 var 声明的变量具有函数作用域,意味着它们只在声明它们的函数内部可见。
  3. 块级作用域:使用 letconst 声明的变量具有块级作用域,意味着它们只在声明它们的块或子块内可见。
// 1. 全局作用域var globalVar ="全局作用域";functionglobalScopeExample(){
  console.log(globalVar);// 输出 "全局作用域"}globalScopeExample();// 2. 函数作用域functionfunctionScopeExample(){var functionVar ="函数作用域";
  console.log(functionVar);// 输出 "函数作用域"}functionScopeExample();// console.log(functionVar); // 报错,functionVar 不在作用域内// 3. 块级作用域if(true){let blockLet ="块级作用域 let";const blockConst ="块级作用域 const";
  console.log(blockLet);// 输出 "块级作用域 let"
  console.log(blockConst);// 输出 "块级作用域 const"}// console.log(blockLet); // 报错,ReferenceError: blockLet is not defined// console.log(blockConst); // 报错,ReferenceError: blockConst is not defined

变量提升(Hoisting)

变量提升是指 JavaScript 在执行代码时会将变量声明提升到作用域的顶部。使用

var

声明的变量会被提升,而

let

const

声明的变量不会被提升。详细内容请看文章【😤 踩了个小水坑】JavaScript不仅有变量声明,还有变量提升

console.log(varVar);// 输出 undefinedvar varVar ="小明";// console.log(letVar); // 报错,Cannot access 'letVar' before initializationlet letVar ="小薇";// console.log(constVar); // 报错,Cannot access 'constVar' before initializationconst constVar ="小刚";
var

声明的

varVar

变量被提升,因此在

console.log(varVar)

时输出

undefined

,而

let

const

声明的变量不会被提升,因此在声明前使用会导致错误。

暂时性死区(Temporal Dead Zone, TDZ)

TDZ 是指在

let

const

声明的变量从作用域开始到初始化之间的时间段。在 TDZ 内访问这些变量会导致引用错误。这种现象的原因是,在变量声明之前的区域被称为暂时性死区。

{// TDZ开始// console.log(c); // 报错,c在TDZ中let c =10;// TDZ结束
  console.log(c);// 输出 10}

WX20231120-135436@2x.png

优缺点对比:let、const、var

在JavaScript中,

let

const

var

各有其独特的特点和应用场景。通过比较它们的优缺点,可以帮助我们更好地选择合适的变量声明方式。
特性

let
const
var

作用域块级作用域块级作用域函数作用域重新赋值允许不允许允许提升(Hoisting)不会,声明前使用会导致引用错误不会,声明前使用会导致引用错误会,被提升到函数或全局作用域顶部暂时性死区(TDZ)是是否必须初始化否是否常见用途循环变量、条件语句、块级作用域常量、不可变对象、函数引用全局变量、函数变量、在ES5及之前的代码中使用安全性高,避免变量提升和作用域污染高,避免变量提升和作用域污染低,易引起作用域污染和意外的变量重定义内存管理优,块级作用域帮助释放内存优,块级作用域帮助释放内存差,变量提升和全局作用域易导致内存泄漏可维护性高,代码结构清晰,易于维护高,代码结构清晰,易于维护低,易引起混乱和难以维护
可以看出,

let

const

提供了块级作用域和更高的安全性,适用于现代 JavaScript 开发,而

var

由于其函数作用域和变量提升特性,已逐渐被淘汰。

高级技巧与实际应用

我们将探讨

let

const

在一些高级技巧和实际应用中的使用方法,包括模块化开发以及结合ES6+新特性的现代化应用。

模块化开发

模块化开发中,

let

const

可以帮助避免全局命名空间的污染,提高代码的可维护性和重用性。

// module.jsexportconstPI=3.14;// main.jsimport{PI}from'./module.js';
console.log(PI);// 输出 3.14

在这个例子中,

PI

常量通过

const

在模块间传递和使用,保证了值的不可变性和代码的清晰性。

解构赋值

解构赋值是一种便捷的方式,可以从数组或对象中提取值并赋给变量。

const user ={name:'Alice',age:25,address:{city:'Wonderland'}};// 对象解构赋值const{ name, age,address:{ city }}= user;
console.log(name, age, city);// 输出 'Alice 25 Wonderland'// 数组解构赋值const colors =['red','green','blue'];const[first, second, third]= colors;
console.log(first, second, third);// 输出 'red green blue'

模板字符串

模板字符串使用反引号(

`

)包围,允许在字符串中嵌入表达式。

const name ='Alice';const age =25;// 模板字符串const message =`My name is ${name} and I am ${age} years old.`;
console.log(message);// 输出 'My name is Alice and I am 25 years old.'// 多行字符串const multiline =`
  This is a 
  multiline 
  string.
`;
console.log(multiline);

WX20230807-141353@2x.png

常见误区和面试题解析

常见误区:你认为呢?

  • 误以为 const 声明的对象不可变
  • 忽略了 letconst 的块级作用域

面试题解析

题目:

const

定义的对象属性是否可以改变?

const obj ={key:'value'};
obj.key ='newValue';
console.log(obj.key);// 输出 'newValue'

解析:

const

声明的对象引用不可变,但对象的属性是可变的。

结论与展望

通过本文的阅读,希望能对

let

const

在不同应用场景下的优劣势有了更深入的了解,并能在实际开发中应用自如。请在评论区分享你的使用经验或者提出你的疑问,期待与你的互动!


本文转载自: https://blog.csdn.net/qq_37834631/article/details/140289373
版权归原作者 SailingCoder 所有, 如有侵权,请联系我们删除。

“【前端大忌】不要小看 let 和 const,这里面也博大精深”的评论:

还没有评论