JavaScript 声明私有变量的两种方式
JavaScript 原生缺乏私有变量关键字,本文介绍两种实现方式:利用闭包封装内部状态,以及利用 WeakMap 的 key 不可枚举特性。通过具体代码示例,展示了如何在对象操作中限制外部访问,从而强化类型控制并保护数据完整性。
前言
JavaScript 语言机制不同于其他编程语言,它没有直接的关键字用于声明私有变量。目前了解到的实现私有变量的主要手段包括利用闭包机制以及使用 WeakMap 对象。
闭包
关于闭包的定义有多种表述,例如:能够访问其他函数作用域的函数;或者是连接内部函数与外部函数作用域的桥梁等。
利用闭包构建私有变量的核心逻辑如下: 1. 在外部函数中定义变量及内部函数; 2. 通过内部函数读取或修改这些变量; 3. 在外部函数中返回内部函数,从而暴露访问接口。
function outside(){
let val = 123;
function inside(){
return val;
}
return inside;
}
console.log(outside()());//123
上述示例展示了闭包构建私有变量的基本逻辑,但这并不能完全体现私有变量的核心价值,因为一个 const 常量也能实现类似的数据访问效果。
//同样的能访问,但是不能修改,达到了上述代码的效果
const val = 123;
console.log(val);//123
接下来的代码将具体展示私有变量在数据保护方面的重要性。
function person(){
let _name = 'unknown';
let _age = 18;
let _sex = 'man';
function setName(name){
_name = name || 'unknown';
}
function getName(){
return _name;
}
function setAge(age){
if(typeof age === 'number'){
_age = Math.floor(age);
}else{
throw Error("typeof age !== 'number'");
}
}
function getAge(){
return _age;
}
function setSex(sex){
if(sex === 'man' || sex === 1){
_sex = 'man';
}else if(sex === 'woman' || sex === 0){
_sex = 'woman';
}else{
throw Error('input error');
}
}
function getSex(){
return _sex;
}
return {
setName : setName,
getName : getName,
setAge : setAge,
getAge : getAge,
setSex : setSex,
getSex : getSex
}
}
let xiaoming = person();
let xiaohong = person();
xiaoming.setName('xiaoming');
xiaohong.setName('xiaohong');
console.log('xiaoming name : ' + xiaoming.getName());//xiaoming name : xiaoming
console.log('xiaohong name : ' + xiaohong.getName());//xiaohong name : xiaohong
xiaoming.setAge(19.3333);
xiaohong.setAge('16');//Uncaught Error: typeof age !== 'number'
console.log('xiaoming age : ' + xiaoming.getAge());//xiaoming age : 19
console.log('xiaohong age : ' + xiaohong.getAge());//xiaohong age : 18
xiaoming.setSex(1);
xiaohong.setSex('woman');
console.log('xiaoming sex : ' + xiaoming.getSex());//xiaoming sex : man
console.log('xiaohong sex : ' + xiaohong.getSex());//xiaohong sex : woman
从上述代码可以看出,若要设置或获取 _name、_age、_sex 这三个变量的值,必须通过特定的 setName、getName、setAge、getAge、setSex、getSex 等方法进行。所有 setter 方法均对传入参数进行了类型或范围校验。这意味着对象的所有操作均处于受控状态,这在一定程度上缓解了 JavaScript 作为弱类型语言可能带来的负面影响。
WeakMap
若对 WeakMap 不熟悉,建议先查阅其详细介绍。此处主要利用 WeakMap 的 key 不可枚举这一特性来实现私有变量。
let nameWeakMap = new WeakMap();
let ageWeakMap = new WeakMap();
let sexWeakMap = new WeakMap();
function person(){
let _hash = Object.create(null);
nameWeakMap.set(_hash,'unknown');
ageWeakMap.set(_hash,18);
sexWeakMap.set(_hash,'man');
function setName(name){
nameWeakMap.set(_hash,name || 'unknown');
}
function getName(){
return nameWeakMap.get(_hash);
}
function setAge(age){
if(typeof age === 'number'){
ageWeakMap.set(_hash,Math.floor(age));
}else{
throw Error("typeof age !== 'number'");
}
}
function getAge(){
return ageWeakMap.get(_hash);
}
function setSex(sex){
if(sex === 'man' || sex === 1){
sexWeakMap.set(_hash,'man');
}else if(sex === 'woman' || sex === 0){
sexWeakMap.set(_hash,'woman');
}else{
throw Error('input error');
}
}
function getSex(){
return sexWeakMap.get(_hash);
}
return {
setName : setName,
getName : getName,
setAge : setAge,
getAge : getAge,
setSex : setSex,
getSex : getSex
}
}
let xiaoming = person();
let xiaohong = person();
xiaoming.setName('xiaoming');
xiaohong.setName('xiaohong');
console.log('xiaoming name : ' + xiaoming.getName());//xiaoming name : xiaoming
console.log('xiaohong name : ' + xiaohong.getName());//xiaohong name : xiaohong
xiaoming.setAge(19.3333);
xiaohong.setAge('16');//Uncaught Error: typeof age !== 'number'
console.log('xiaoming age : ' + xiaoming.getAge());//xiaoming age : 19
console.log('xiaohong age : ' + xiaohong.getAge());//xiaohong age : 18
xiaoming.setSex(1);
xiaohong.setSex('woman');
console.log('xiaoming sex : ' + xiaoming.getSex());//xiaoming sex : man
console.log('xiaohong sex : ' + xiaohong.getSex());//xiaohong sex : woman
这种方法同样实现了构建私有变量的效果。值得一提的是,ES6 class 中构建私有变量时使用的正是 WeakMap 机制。
结尾
本文仅记录我所了解的 JavaScript 构建私有变量的方法及作用。如有错误或遗漏,欢迎指正,不胜感激。
以上就是 JavaScript 声明私有变量的两种方式的详细内容,更多关于 JavaScript 声明私有变量的资料请关注本站其它相关文章!
JS动态构建复杂嵌套JSON对象的方法
2026-11-05 15:41:52
JS负数取余为什么是负数?详解余数与模运算区别
2026-11-05 13:34:41
JS 解压出现乱码或报错怎么解决?
2026-11-05 12:32:38
JS 中 startsWith、indexOf 与正则判断字符串前缀的对比
2026-11-04 22:19:43
JS解析Excel后怎么将数据转换为JSON格式
2026-11-04 20:58:28
