前端私有化变量还只会加前缀嘛?保姆级教程教你4种私有化变量方法

在 JavaScript 开发中,封装是一个至关重要的编程概念。它通过隐藏对象内部的实现细节,只暴露必要的接口,来保证代码的稳定性、安全性和可维护性。私有化变量作为封装的核心手段,在 JavaScript 中的实现方式经历了显著的演进。

本文将系统梳理 JavaScript 中实现私有化的四种主要方式,分析其原理、优缺点和适用场景,帮助开发者做出正确的技术选型。

1. 约定俗成版:下划线命名约定

实现方式与原理

在 ES6 之前,JavaScript 没有语法层面的私有成员,社区形成了使用下划线 _ 作为前缀的命名约定。

javascript 复制代码
class MyClass {
  constructor() {
    this._privateValue = 10; // "假装"是私有属性
  }

  _privateMethod() {
    console.log('这是一个私有方法');
  }

  getValue() {
    return this._privateValue; // 通过公共方法访问
  }
}

const instance = new MyClass();
console.log(instance.getValue()); // 10 (正确方式)
console.log(instance._privateValue); // 10 (仍然可以直接访问)
instance._privateMethod(); // 仍然可以直接调用

优缺点分析

优点:

  • 实现简单,无需额外语法
  • 兼容性极好,所有 JavaScript 环境都支持

缺点:

  • 毫无强制约束力,全靠开发者自觉
  • 无法真正保证封装性,外部代码仍可随意访问和修改

2. 闭包版:真正的私有化方案

实现原理

利用函数作用域闭包特性模拟真正的私有变量,是 ES6 之前最可靠的方案。

两种实现方式

方式一:构造函数中实现

javascript 复制代码
function MyClass() {
  // 真正的私有变量,只在构造函数作用域内可访问
  let privateValue = 10;

  this.getPrivateValue = function() {
    return privateValue; // 公共方法通过闭包访问私有变量
  };

  this.setPrivateValue = function(val) {
    privateValue = val;
  };
}

const instance = new MyClass();
console.log(instance.getPrivateValue()); // 10
console.log(instance.privateValue); // undefined (真正私有)

方式二:模块模式(IIFE)

javascript 复制代码
const MyModule = (function() {
  let privateCounter = 0; // 私有变量

  return {
    increment: function() {
      privateCounter++;
    },
    getValue: function() {
      return privateCounter;
    }
  };
})();

MyModule.increment();
console.log(MyModule.getValue()); // 1
console.log(MyModule.privateCounter); // undefined (无法访问)

优缺点分析

优点:

  • 实现真正的私有化,外部无法直接访问
  • 兼容性好,支持所有 JavaScript 环境

缺点:

  • 写法繁琐,代码组织不够清晰
  • 构造函数方式中,私有方法需要在每个实例上都创建一遍,占用更多内存

3. Symbol 版:半私有化方案

实现原理

利用 Symbol 的唯一性来创建"不易被外部访问"的属性。

javascript 复制代码
const _privateKey = Symbol('privateKey');
const _privateMethodKey = Symbol('privateMethodKey');

class MyClass {
  constructor() {
    this[_privateKey] = 10; // 使用 Symbol 作为键
  }

  publicMethod() {
    return this[_privateKey];
  }

  // "私有"方法
  [_privateMethodKey]() {
    console.log('私有方法被调用');
  }
}

const instance = new MyClass();
console.log(instance.publicMethod()); // 10

// 仍然可以被"绕过"
const symbolKey = Object.getOwnPropertySymbols(instance)[0];
console.log(instance[symbolKey]); // 10

优缺点分析

优点:

  • 比下划线方式更隐蔽
  • 语法相对简洁

缺点:

  • 并非真正私有 ,可通过 Object.getOwnPropertySymbols() API 获取到 Symbol 键
  • 只是增加了访问难度,无法保证真正的封装性

4. ES13+ 正式版:语法级私有字段

实现方式

ES2019 引入了 # 前缀 来在类中声明真正的私有字段,这是目前官方推荐的方案。

javascript 复制代码
class MyClass {
  // 声明私有字段(必须声明)
  #privateValue;
  #anotherPrivateValue = 42;

  // 私有方法
  #privateMethod() {
    console.log('我是私有方法');
    return this.#privateValue;
  }

  constructor(value) {
    this.#privateValue = value;
  }

  // 公共方法接口
  getPrivateValue() {
    return this.#privateMethod();
  }

  setPrivateValue(value) {
    if (typeof value === 'number') {
      this.#privateValue = value;
    }
  }
}

const instance = new MyClass(10);
console.log(instance.getPrivateValue());

// 以下访问都会抛出错误
console.log(instance.#privateValue); // SyntaxError
console.log(instance['#privateValue']); // TypeError
instance.#privateMethod(); // SyntaxError

优缺点分析

优点:

  • 真正私有:语法层面强制,外部无法以任何方式访问
  • 语法简洁 :使用简单直观的 # 前缀
  • 强大的封装:可在 setter 中加入验证逻辑,保证数据有效性

缺点:

  • 需要先声明私有字段
  • 较老环境不支持,需要 Babel 等工具转换

总结与对比

方式 优点 缺点 推荐度
_ 约定 简单,兼容性极好 无强制力,形同虚设 ⭐⭐
闭包 真正私有,兼容性好 写法繁琐,内存占用高 ⭐⭐⭐
Symbol _ 更隐蔽 仍可被反射 API 破解 ⭐⭐
# 语法 真正私有,语法简洁,官方标准 需要声明,老环境需编译 ⭐⭐⭐⭐⭐

您好,我是肥晨。 欢迎关注我获取前端学习资源,日常分享技术变革,生存法则;行业内幕,洞察先机。

相关推荐
让我上个超影吧2 分钟前
基于SpringBoot和Vue实现CAS单点登录
前端·vue.js·spring boot
军军君0121 分钟前
Three.js基础功能学习五:雾与渲染目标
开发语言·前端·javascript·学习·3d·前端框架·three
程序员爱钓鱼23 分钟前
Node.js 编程实战:RESTful API 设计
前端·后端·node.js
程序员爱钓鱼25 分钟前
Node.js 编程实战:GraphQL 简介与实战
前端·后端·node.js
chilavert31843 分钟前
技术演进中的开发沉思-284 计算机原理:二进制核心原理
javascript·ajax·计算机原理
罗技1231 小时前
Easysearch 集群监控实战(下):线程池、索引、查询、段合并性能指标详解
前端·javascript·算法
XiaoYu20021 小时前
第3章 Nest.js拦截器
前端·ai编程·nestjs
千寻girling1 小时前
面试官 : “ 说一下 Map 和 WeakMap 的区别 ? ”
前端·javascript·面试
2501_924064111 小时前
2025年主流Web自动化测试工具功能与适用场景对比
前端·测试工具·自动化
可触的未来,发芽的智生1 小时前
一万个为什么:频率和相位
javascript·人工智能·python·程序人生·自然语言处理