JavaScript中的常量-除了’const‘你还知道几种?
职场小段子
在繁忙的CodeCity,每个程序员都在自己的工作站上耕耘着,而李浩,一个对代码有着近乎偏执追求的中级开发者,正在为一个看似简单的常量问题头疼。 “李浩,你又在纠结什么?”同事小王打趣地问。 “哎,我在想,我们用‘const’声明了一个常量,但好像并不是那么‘常量’。”李浩皱着眉头回答。 小王好奇地凑过来:“怎么说?” 李浩打开编辑器,敲了一段代码:“你看,我用‘const’声明了一个对象和一个数组。”
const MY_OBJ = { key: 'value' };
const MY_ARRAY = [1, 2, 3];
他继续说:“我以为这样就能保证它们不被修改,但你看下面的操作。”
MY_OBJ.key = 'new value'; // 属性被修改了
MY_ARRAY.push(4); // 数组被修改了
小王一愣:“啊,这...这不是和我们公司的年度预算一样吗?说是固定不变,结果每次会议都能给你调整一下。” 李浩苦笑:“对啊,所以光用‘const’是不够的。我们需要更强大的武器,比如Object.freeze()。” 他迅速修改了代码:
const IMMUTABLE_OBJ = Object.freeze({ key: 'value' });
const IMMUTABLE_ARRAY = Object.freeze([1, 2, 3]);
IMMUTABLE_OBJ.key = 'attempted change'; // 无效
IMMUTABLE_ARRAY.push(4); // 无效,但不会报错,需要额外处理
李浩解释道:“现在,IMMUTABLE_OBJ和IMMUTABLE_ARRAY是真的‘冻住’了,任何修改都不会生效。这就好比我们的代码库,有了严格的代码审查流程,不允许随意更改。” 小王点头:“那如果我想创建一个真正的常量类,该怎么办?” 李浩微笑:“这时候,我们可以用闭包来模拟私有变量,保证外部无法修改。” 他展示了一段代码:
const ConstantClass = (function() {
let _privateValue = 'I am private';
return {
getValue: function() {
return _privateValue;
}
};
})();
console.log(ConstantClass.getValue()); // 'I am private'
// ConstantClass._privateValue 是无法访问的
小王眼睛一亮:“原来如此,这就是传说中的‘封装’吧!” 李浩点头:“没错,常量的世界很深奥,不只是‘const’那么简单。掌握了这些技巧,我们的代码才能真正做到‘稳如老狗’。” 两人相视一笑,继续投入到代码的世界中,每一次键入,都是对常量深刻理解的体现。
一、基础使用:const关键字
自从ES6标准推出以来,const关键字已经成为定义常量的首选方式了。const声明的变量在赋值后,它的值就不能被重新赋值了。 代码:
const PI = 3.14159; // 常量PI的值不能被改变
而且在实际开发中,使用const定义常量可以避免因意外修改导致的程序错误,提高代码的稳定性。
但是要注意引用类型里面的值是可以改变的:
const fruits = ['apple', 'banana']; // 引用类型常量
尽管 fruits 被声明为常量,但其内部元素仍可被修改:
fruits.push('cherry'); // 允许修改数组内的元素
二、对象属性的不可变性:Object.defineProperty
但是在JavaScript中,对象是引用类型,其属性值是可以被修改的。为了实现对象属性的不可变性,我们可以使用Object.defineProperty方法。 代码:
let settings = {};
Object.defineProperty(settings, 'MAX_USERS', {
value: 0,
writable: false, // 属性值不可改
configurable: false // 不能删除或重新定义此属性
});
通过这种方式,我们可以精确控制对象属性的不可变性,适用于需要对特定属性进行保护的场景。
当我们去修改MAX_USERS
属性时,它并不能成功
settings.MAX_USERS = 1
console.log(settings.MAX_USERS); // 0
依旧打印的是0
Object.defineProperty 不仅可以用来创建只读属性,还可以设置属性的枚举性和可配置性。例如:
let config = {};
Object.defineProperty(config, 'maxUsers', {
value: 100,
writable: false,
enumerable: true, // 可以在for...in循环中枚举
configurable: false
});
此外,Object.defineProperty 还可以用来创建 getter 和 setter,这在实现属性的计算或验证逻辑时非常有用。
三、冻结对象:Object.freeze
有时候,我们需要让整个对象成为不可变,包括其所有属性。这时,可以使用Object.freeze方法。该方法会阻止修改、添加或删除任何属性。 代码:
const config = {
apiKey: "abcdef12345"
};
Object.freeze(config); // config对象现在完全不可变
当我去修改apiKey 的值时
并不能成功
Object.freeze方法适用于配置对象、枚举等场景,确保数据在整个应用中的稳定性。
四、使用立即执行函数表达式(IIFE)和闭包保护常量
在ES6之前,JavaScript没有提供原生的常量定义方式。我们通常会利用立即执行函数和闭包来模拟常量行为。 代码:
const CONSTANT = (function() {
let value = 42;
return {
getValue: function() {
return value;
}
};
})();
// 这里CONSTANT.value不存在,只能通过CONSTANT.getValue()访问值
通过这种方式,我们可以保护内部变量,使其在外部无法直接修改。这种方法在早期JavaScript代码中较为常见,如今虽然有了const关键字,但在某些特定场景下,仍具有一定的实用价值。
总结:
我们发现“const”不仅是简单的值锁定机制,它开启了一扇通往更深层次代码控制的大门。从基本的“const”声明,到利用“Object.defineProperty”和“Object.freeze”实现对象属性的不可变性,再到运用闭包和IIFE保护常量免受外界干扰,每一步都揭示了“const”背后的广阔天地。总结而言,“JavaScript常量:‘const’是答案,问题是什么”引出了关于代码稳定性和数据保护的深刻讨论,教导我们如何在复杂的应用环境中构建不可动摇的基石,确保程序的健壮性和维护性。
转载自:https://juejin.cn/post/7390339205974638611