ES6中const声明的完整机制与内存管理解析

作者:青柠时间:2026-10-30 23:04:57浏览:641

本文深入解析ES6中const关键字的核心特性,包括其块级作用域、禁止重复声明、不存在变量提升及暂时死区机制。重点阐述const对基本类型与引用类型的不同影响,解释为何对象属性可修改而地址不可变,并演示如何使用Object.freeze实现深层冻结,最后提供const与let的选择建议。

在ES6规范中,通过const声明的变量不具备全局挂载特性,即不会成为顶层对象window的属性。

利用const关键字定义的变量,其作用域受限,不会自动挂载到window对象上。

const a = 5
console.log(a)
console.log(window.a)
// 5
// undefined

const关键字严格禁止对同一标识符进行重复声明。

若尝试使用const重复声明已存在的变量,引擎将抛出语法错误。

cosnt a = 5
cosnt a = 6
// Uncaught SyntaxError: Unexpected identifier 'a'
不能重复声明a

与var不同,const声明不具备变量提升特性。

const声明的变量不会在代码解析阶段提前至作用域顶部,而是在执行流到达该语句时才进行声明。

暂时死区(TDZ)是ES6引入的重要概念。

若在const声明语句之前访问该变量,将触发引用错误,此区间称为暂时死区。

if(true) {
    console.log(a)
    const a = 5
}
// Uncaught ReferenceError: Cannot access 'a' before initialization
// 初始化前无法访问a

const声明引入了块级作用域的概念。

在大括号{}内部使用const声明的变量,其可见性仅限于该代码块内部,外部无法访问。

if (true) {
	const a = 5
}
console.log(a)
// Uncaught ReferenceError: a is not defined
// a 再大括号外没有声明

const具有区别于其他声明方式的独有行为特征。

定义层面,const声明的变量被称为常量。

常量一旦绑定值便不可重新赋值,这是const的基本约束。

声明常量的方式在ES5与ES6中存在差异。

在ES5环境中,通常通过Object.defineProperty定义只读属性来模拟常量。

// 定义一个新的属性
Object.defineProperty(window, 'PI', {
	value: 3.14,
	writable: false, // 是否可修改的, false表示不可以修改
})
console.log(PI) // 3.14
PI = 5
console.log(PI) // 3.14 ,因为不可以被修改

ES6标准直接提供了const关键字用于声明常量。

const a = 5;
a = 6;
// Uncaught TypeError: Assignment to constant variable.
// 不能修改常量的值

const声明必须在初始化时赋予初始值。

const a;
a = 5
//  Uncaught SyntaxError: Missing initializer in const declaration
// 常量必须再声明时赋值

当const声明的对象类型变量时,其内部属性可以被修改。

const obj = {
	name: 'xiaoxiao',
	age: 18
}
console.log(obj)
// {name: 'xiaoxiao', age: 18}
obj.school = 'imooc'
console.log(obj)
// {name: 'xiaoxiao', age: 18, school: 'imooc'}

理解JavaScript的内存存储机制是掌握const行为的关键。

JavaScript主要包含栈内存(stack)和堆内存(heap)两种存储区域。

基本数据类型,包括Boolean、Null、Undefined、Number、String和Symbol,其值直接存储在栈内存中。

引用数据类型,如Object(涵盖数据对象、函数、正则表达式等),其引用指针存储在栈中,实际数据存储在堆内存中。

在ES6规范中,通过const声明的变量不具备全局挂载特性,即不会成为顶层对象window的属性。

若const声明的是基本数据类型,由于值存储在栈中且不可变,因此无法重新赋值。

若const声明的是引用数据类型,数据存储在堆中,const仅锁定栈中的内存地址,不限制堆中内容的修改。

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

PS: const定义的变量,基本数据类型不能够被重新赋值,引用数据类型可以被重新赋值, 因为引用数据类型真正是存储在堆内存里面的,const声明的常量不改动,指的是变量所指向的哪个内存地址不能改动,引用数据类型引用地址没有改变,只是地址里面存储的东西改变了。

形象比喻:基本类型如同具体的实物(如苹果),内容固定不可替换;引用类型如同容器(如书包),内部物品可更换但容器本身不变。

引用类型变量如同容器,如书包或盒子,内部存放的物品(数据)可以改变,但容器(引用地址)保持不变。

如何确保const声明的对象变量内容不可被修改?

使用Object.freeze方法可以冻结对象的属性,使其不可修改。

const obj = {
	name: 'xiaoxiao',
	age: 18
}
Object.freeze(obj)
console.log(obj)
// {name: 'xiaoxiao', age: 18}
obj.school = 'imooc'
console.log(obj)
// {name: 'xiaoxiao', age: 18}

Object.freeze仅能冻结对象的第一层属性。

const obj = {
	name: 'xiaoxiao',
	age: 18,
    sikll: {
        name: 'code',
        year: 11
    }
}
Object.freeze(obj)
obj.school = 'imooc'
obj.sikll.year = 13
console.log(obj)
/*
{
    "name": "xiaoxiao",
    "age": 18,
    "sikll": {
        "name": "code",
        "year": 13
    }
}
*/

对于嵌套的第二层属性,Object.freeze默认无法进行冻结保护。

需要手动对嵌套对象再次调用冻结方法以实现深层冻结。

const obj = {
	name: 'xiaoxiao',
	age: 18,
    sikll: {
        name: 'code',
        year: 11
    }
}
Object.freeze(obj) // 冻结第一层属性,不可以被修改
Object.freeze(obj.sikll) // 冻结第二层属性,不可以被修改
obj.school = 'imooc'
obj.sikll.year = 13
console.log(obj)
/*
{
    "name": "xiaoxiao",
    "age": 18,
    "sikll": {
        "name": "code",
        "year": 11
    }
}
*/

对数组应用Object.freeze后,尝试添加新元素会抛出类型错误。

const arr = [1,2,3]
Object.freeze(arr)
arr.push(4)
console.log(arr)
// Uncaught TypeError: Cannot add property 3, object is not extensible
// 无法添加属性 3,对象不可扩展

const与let的使用场景选择。

定义变量时,若预判后续逻辑中变量值不会改变,应优先使用const;若可能改变,则使用let。

本文介绍了ES6中const声明的核心机制,更多相关技术细节请参阅本站其他文章或关注后续更新。

作者最新文章