前端私有化变量还只会加前缀嘛?保姆级教程教你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 破解 ⭐⭐
# 语法 真正私有,语法简洁,官方标准 需要声明,老环境需编译 ⭐⭐⭐⭐⭐

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

相关推荐
一枚前端小能手4 分钟前
🔥 SSR服务端渲染实战技巧 - 从零到一构建高性能全栈应用
前端·javascript
Komorebi_99994 分钟前
Vue3 provide/inject 详细组件关系说明
前端·javascript·vue.js
用户14125016652718 分钟前
一文彻底掌握 ECharts:从配置解读到实战应用
前端
LRH20 分钟前
React 架构设计:从 stack reconciler 到 fiber reconciler 的演进
前端
VIjolie21 分钟前
文档/会议类应用的协同同步机制(OT/CRDT简要理解)
前端
不一样的少年_23 分钟前
【前端效率工具】:告别右键另存,不到 50 行代码一键批量下载网页图片
前端·javascript·浏览器
golang学习记23 分钟前
从0死磕全栈之Next.js 企业级 next.config.js 配置详解:打造高性能、安全、可维护的中大型项目
前端
1024小神26 分钟前
next项目使用状态管理zustand说明
前端
Asort26 分钟前
JavaScript设计模式(八):组合模式(Composite)——构建灵活可扩展的树形对象结构
前端·javascript·设计模式
刘永胜是我28 分钟前
【iTerm2 实用技巧】解决两大顽疾:历史记录看不全 & 鼠标滚轮失灵
前端·iterm