你不会还不知道 Symbol 的使用场景的吧

在 JavaScript 中,Symbol 是一种特殊的原始数据类型(第 7 种类型),它的核心价值是创建唯一且不可变的标识符。以下是 7 个最典型的实际运用场景:

一、防属性名冲突的「加密锁」

场景:多人协作开发时,防止对象属性被意外覆盖

js 复制代码
// 你和同事各自给对象添加属性
const user = { 
  name: '小明' 
};

// 你用 Symbol 添加「身高」属性
const heightSymbol = Symbol('height');
user[heightSymbol] = 180; 

// 同事用普通字符串添加同名属性
user.height = '180cm'; 

console.log(user.height); // '180cm'(同事的)
console.log(user[heightSymbol]); // 180(你的) 

比喻:就像在共享储物柜里,你用带唯一钥匙的锁头(Symbol),别人用普通挂锁(字符串属性),互不干扰

二、定义类的「私有成员」

场景:模拟类的私有属性(虽然 JS 没有真正的私有属性)

js 复制代码
const _password = Symbol('password');

class User {
  constructor(name, pwd) {
    this.name = name;
    this[_password] = pwd; // 用 Symbol 存储密码
  }

  checkPassword(pwd) {
    return this[_password] === pwd;
  }
}

const user = new User('张三', '123456');
console.log(user[_password]); // 可以访问(但需要 Symbol 引用)
console.log(Object.keys(user)); // ['name'](无法通过常规方式遍历)

注意:这不是真正的私有,但能防止意外访问

三、系统级标识的「魔法钥匙」

场景:使用内置 Symbol 改变对象行为

js 复制代码
// 让对象可迭代
const myCollection = {
  [Symbol.iterator]: function* () {
    yield 1;
    yield 2;
    yield 3;
  }
};

console.log([...myCollection]); // [1, 2, 3]

// 自定义对象的 toString 标签
const secretBox = {
  [Symbol.toStringTag]: '🕵️♂️机密盒子'
};
console.log(secretBox.toString()); // [object 🕵️♂️机密盒子]

常用内置 Symbol

  • Symbol.iterator:定义迭代器
  • Symbol.toStringTag:控制 Object.prototype.toString 输出
  • Symbol.hasInstance:自定义 instanceof 行为

四、定义唯一常量值的「防伪标识」

场景:需要保证值绝对唯一的常量

js 复制代码
// 传统方式(可能重复)
const LOG_LEVEL = {
  DEBUG: 1,
  INFO: 2,
  WARN: 3,
  ERROR: 4
};

// 使用 Symbol(绝对唯一)
const LOG_LEVEL = {
  DEBUG: Symbol('debug'),
  INFO: Symbol('info'),
  WARN: Symbol('warn'),
  ERROR: Symbol('error')
};

function log(message, level) {
  if (level === LOG_LEVEL.DEBUG) {
    console.debug(message);
  }
  // ...
}

优势:避免用数字/字符串可能导致的意外匹配

五、元编程的「魔法标记」

场景:在框架/库开发中标记特殊属性

js 复制代码
// Vue3 源码中的标记示例
const SKIP = Symbol('skip');
const component = {
  [SKIP]: true, // 标记该组件跳过某些处理
  // ...
};

// React 中的 $$typeof 标记
// 用于防止 XSS 攻击(伪代码)
const element = {
  $$typeof: Symbol.for('react.element'),
  // ...
};

六、注册全局共享的「国际护照」

场景:跨模块/窗口共享同一个 Symbol

js 复制代码
// 模块A.js
export const CACHE_KEY = Symbol.for('app.cache');

// 模块B.js
import { CACHE_KEY } from './A.js';
console.log(CACHE_KEY === Symbol.for('app.cache')); // true

注意Symbol.for() 会在全局注册表中创建/查找 Symbol

七、防止 XSS 攻击的「安全盾」

场景:React 使用 Symbol 保护元素对象

js 复制代码
// React 元素对象结构(简化)
const element = {
  $$typeof: Symbol.for('react.element'),
  type: 'div',
  props: {}
};

// 如果攻击者伪造元素对象:
const fakeElement = {
  type: 'script',
  props: { dangerouslySetInnerHTML: { __html: '恶意代码' } }
};

// React 会检查 $$typeof 属性
if (element.$$typeof !== Symbol.for('react.element')) {
  throw new Error('非法元素!');
}

Symbol 特性总结表

特性 说明
唯一性 Symbol('desc') !== Symbol('desc')
不可变性 创建后无法修改
不可枚举性 不参与 for...in / Object.keys() 遍历
全局注册 Symbol.for('key') 可跨模块共享
类型检测 typeof Symbol() === 'symbol'

什么时候不该用 Symbol?

  • 需要序列化数据时(JSON.stringify 会忽略 Symbol 属性)
  • 需要显式暴露给外部使用的属性
  • 低版本浏览器兼容性要求高时(IE 不支持)

以上内容来自 AI,有什么需要改正的在评论开喷谢谢

相关推荐
Carlos_sam4 分钟前
OpenLayers:封装Tooltip
前端·javascript
工呈士17 分钟前
MobX与响应式编程实践
前端·react.js·面试
嘉小华18 分钟前
Android Lifecycle 使用
前端
Sherry00720 分钟前
实时数据传输协议:WebSocket vs MQTT
前端·websocket
然我21 分钟前
JavaScript的OOP独特之道:从原型继承到class语法
前端·javascript·html
腹黑天蝎座23 分钟前
如何更好的实现业务中图片批量上传需求
前端
嘉小华24 分钟前
Android Lifecycle 源码解析
前端
不_喜24 分钟前
游戏开发零散知识点和优化记录
前端
去伪存真33 分钟前
提交规范靠吼没用,看我用“shell+husky螺丝刀”,一键给40多个项目上锁
前端·eslint
翠莲43 分钟前
vue3+TS+eslint9配置
前端·代码规范