前端私有化变量还只会加前缀嘛?保姆级教程教你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 小时前
《搭建属于自己的网站之网页前端学习》基础入门
前端·学习
刘一说3 小时前
深入理解 Spring Boot 嵌入式 Web 容器:从原理到性能调优
前端·spring boot·firefox
你的人类朋友3 小时前
设计模式的原则有哪些?
前端·后端·设计模式
!执行4 小时前
Web3 前端与合约交互
前端·web3·1024程序员节
潘小安4 小时前
跟着 AI 学(二)- Quill 接入速通
前端
十里-4 小时前
在 Vue2 中为 Element-UI 的 el-dialog 添加拖拽功能
前端·vue.js·ui
shada4 小时前
从Google Chrome商店下载CRX文件
前端·chrome
左耳咚4 小时前
项目开发中从补码到精度丢失的陷阱
前端·javascript·面试
D_C_tyu4 小时前
Vue3 + Element Plus 实现前端手动分页
javascript·vue.js·elementui
黑云压城After4 小时前
vue2实现图片自定义裁剪功能(uniapp)
java·前端·javascript