JavaScript 中的变量声明与对象管理
let 的使用
在块级作用域中,变量名和函数名不能重复。
{
let a = 1;
function a() {
// 函数体
}
console.log(a);
// SyntaxError: Identifier 'a' has already been declared
}
函数提升仅在当前的块级作用域内有效,即提升到其父级作用域,但无法提升到更外层的作用域。
{
let a = 1;
{
function a() {
// 函数体
}
}
console.log(a); // 1
}
const(常量)
定义常量时,必须立即赋值。
const a;
// SyntaxError: Missing initializer in const declaration
常量的值不可被重新赋值。
const a = 1;
a = 10;
console.log(a);
// TypeError: Assignment to constant variable.
暂时性死区
const
不支持变量提升。
{
const a = 10;
}
console.log(a);
// ReferenceError: a is not defined
在初始化之前无法访问 a
。
{
// ReferenceError: Cannot access 'a' before initialization
console.log(a);
const a = 10;
}
正常情况下,可以正常打印 a
的值。
{
const a = 10;
console.log(a); // 10
}
与 let
类似,const
无法重复声明同一变量名。
{
const a = 10;
let a = 12;
// SyntaxError: Identifier 'a' has already been declared
}
修改 const
对于原始类型,常量的指针指向栈空间的地址,值不可变。
对于引用类型,常量存储在堆内存中,仅保证指针不变,内部的数据结构可以修改。
const obj = {};
obj.name = 'zhangsan';
console.log(obj); // { name: 'zhangsan' }
冻结 const 对象
使用 Object.freeze
方法,可以使对象无法被修改。
const obj = [];
Object.freeze(obj);
obj[0] = 'zhangsan';
console.log(obj); // []
const ibje = {};
Object.freeze(ibje);
ibje.name = 'zhangsan';
console.log(ibje); // {}
冻结 const 对象中的嵌套对象
为了确保 const
对象中的所有嵌套对象也被冻结,可以使用递归函数。
function myFreeze(obj) {
Object.freeze(obj);
for (const key in obj) {
if (typeof obj[key] === 'object' && obj[key] !== null) {
myFreeze(obj[key]);
}
}
}
const person = {
son: {
lisi: 18,
zhangshan: 19,
},
car: ['benz', 'BMW', 'mazda'],
};
myFreeze(person);
person.son.wangwu = 20;
person.car[3] = 'toyota';
console.log(person);
// { son: { lisi: 18, zhangshan: 19 },
// car: [ 'benz', 'BMW', 'mazda' ] }
顶层对象
在 window
上挂载变量是 JavaScript 设计中的一个缺陷,导致未声明的变量会自动成为 window
对象的属性。
a = 1;
console.log(a); // 1
console.log(window.a); // 1
为了避免这种情况,建议始终使用 let
或 const
来声明变量,以防止意外地将变量挂载到全局对象上。
let a = 1;
console.log(a); // 1
console.log(window.a); // undefined
在实际开发中的最佳实践
在实际开发中,合理使用 let
和 const
可以提高代码的可读性和可维护性。以下是一些推荐的最佳实践:
-
优先使用
const
:除非变量需要重新赋值,否则应优先使用const
。这有助于防止意外修改变量的值。 -
避免在全局作用域中声明变量:使用模块化的方式组织代码,减少全局变量的使用,防止命名冲突和意外覆盖。
-
冻结对象时,考虑深度冻结:对于复杂的嵌套对象,使用递归方法确保所有层级的对象都被冻结,防止意外修改。
-
明确变量的作用域:使用块级作用域(
{}
)来限制变量的可见范围,避免变量污染和冲突。
通过遵循这些实践,可以编写出更加健壮和易于维护的 JavaScript 代码。
知识扩展
了解顶层对象的行为有助于避免全局变量带来的问题。例如,在浏览器环境中,window
对象是全局对象,所有全局变量和函数都是其属性。因此,避免在全局作用域中声明变量是维护代码质量的重要步骤。
此外,理解 const
的工作机制对于编写不可变数据结构至关重要。在函数式编程中,不可变性可以减少副作用,提高代码的可预测性和可测试性。