跳到主要内容

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

为了避免这种情况,建议始终使用 letconst 来声明变量,以防止意外地将变量挂载到全局对象上。

let a = 1;
console.log(a); // 1
console.log(window.a); // undefined

在实际开发中的最佳实践

在实际开发中,合理使用 letconst 可以提高代码的可读性和可维护性。以下是一些推荐的最佳实践:

  • 优先使用 const:除非变量需要重新赋值,否则应优先使用 const。这有助于防止意外修改变量的值。

  • 避免在全局作用域中声明变量:使用模块化的方式组织代码,减少全局变量的使用,防止命名冲突和意外覆盖。

  • 冻结对象时,考虑深度冻结:对于复杂的嵌套对象,使用递归方法确保所有层级的对象都被冻结,防止意外修改。

  • 明确变量的作用域:使用块级作用域({})来限制变量的可见范围,避免变量污染和冲突。

通过遵循这些实践,可以编写出更加健壮和易于维护的 JavaScript 代码。

知识扩展

了解顶层对象的行为有助于避免全局变量带来的问题。例如,在浏览器环境中,window 对象是全局对象,所有全局变量和函数都是其属性。因此,避免在全局作用域中声明变量是维护代码质量的重要步骤。

此外,理解 const 的工作机制对于编写不可变数据结构至关重要。在函数式编程中,不可变性可以减少副作用,提高代码的可预测性和可测试性。