你不会还不知道 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,有什么需要改正的在评论开喷谢谢

相关推荐
半聋半瞎25 分钟前
【进程和线程】(面试高频考点)
java·jvm·面试
YUELEI11834 分钟前
vue3 使用sass变量
前端·css·sass
Java_young1 小时前
(十七) Nginx解析:架构设计、负载均衡实战与常见面试问题
nginx·面试·负载均衡
枣仁_1 小时前
大型语言模型(LLM)深度解析
前端·javascript·面试
程序员马晓博1 小时前
用上OpenManus啦,这玩意有点像...
前端
鱼樱前端1 小时前
36道我命由我不由天的JavaScript 基础面试题详解
前端·javascript·面试
阿卡好可爱1 小时前
锐势信息的面试
面试·职场和发展
嘉琪coder1 小时前
显示器报废,win笔记本远程连接mac mini4 3种方法实测
前端·windows·mac
hrrrrb2 小时前
【CSS3】筑基篇
前端·css·css3