【JavaScript】手写 Object.prototype.toString()

🔧 ​​一、核心实现原理​​

  1. ​​内部逻辑​​

    • 访问对象的 Symbol.toStringTag 属性(ES6+)或内部 [[Class]] 属性(ES5 及之前)。
    • 若属性不存在,根据对象类型推断默认标签(如 "Object"、"Array")。
    • 返回拼接字符串 "[object " + tag + "]"。
  2. ​​关键特性​​

    • ​不可直接调用​ :需通过 call/apply 绑定 this 指向目标对象。
    • ​优先级​ :Symbol.toStringTag > 内置 [[Class]] 属性。

✨ ​​二、完整代码实现​​

复制代码
Object.defineProperty(Object.prototype, 'toString', {
  value: function() {
    // 1. 处理 null 和 undefined
    if (this === null) return '[object Null]';
    if (this === undefined) return '[object Undefined]';

    // 2. 获取 Symbol.toStringTag 或内部 [[Class]]
    const tag = 
      Symbol.toStringTag in Object(this) 
        ? this[Symbol.toStringTag] 
        : Object.prototype.toString.getInternalClass(this);

    // 3. 返回格式化字符串
    return `[object ${tag}]`;
  },
  writable: true,
  configurable: true
});

// 辅助方法:模拟内部 [[Class]] 检测
Object.prototype.toString.getInternalClass = (obj) => {
  if (Array.isArray(obj)) return 'Array';
  if (obj instanceof Date) return 'Date';
  if (obj instanceof RegExp) return 'RegExp';
  // 其他内置类型判断...
  return 'Object'; // 默认值
};

🧪 ​​三、功能验证​​

1. ​​基本类型检测​​
复制代码
console.log(Object.prototype.toString.call([])); // [object Array]
console.log(Object.prototype.toString.call(new Date())); // [object Date]
console.log(Object.prototype.toString.call(null)); // [object Null]
2. ​​自定义类型标签​​
复制代码
class MyClass {
  get [Symbol.toStringTag]() { return 'MyClass'; }
}
console.log(Object.prototype.toString.call(new MyClass())); // [object MyClass]
3. ​​避免重写影响​​
复制代码
const arr = [];
arr.toString = () => "Overridden!";
console.log(Object.prototype.toString.call(arr)); // 仍输出 [object Array]

⚠️ ​​四、注意事项​​

  1. ​​兼容性处理​​

    • 旧版浏览器(如 IE)需手动实现 Symbol.toStringTag 的 Polyfill。
    • 内部 [[Class]] 在 ES5 后不再直接暴露,需通过类型推断模拟。
  2. ​​性能优化​​

    • 避免频繁调用:每次调用涉及原型链查找和字符串拼接,对性能敏感场景慎用。
  3. ​​与重写方法的区别​​

    • 直接调用 obj.toString() 可能被重写逻辑覆盖,而 Object.prototype.toString.call(obj) 始终访问原始方法。

💡 ​​五、应用场景​​

  1. ​​精准类型判断​ ​

    替代 typeof 和 instanceof,统一处理基本类型和对象类型:

    复制代码
    function getType(obj) {
      return Object.prototype.toString.call(obj).slice(8, -1);
    }
    getType(new Map()); // "Map"
  2. ​​自定义对象描述​ ​

    通过 Symbol.toStringTag 控制调试信息输出:

    复制代码
    class NetworkError {
      get [Symbol.toStringTag]() { return 'NetworkError'; }
    }
    console.log(new NetworkError() + ""); // [object NetworkError]

相关推荐
传人once18 分钟前
悬停旋转放大和位移效果如何写
javascript·css·动画
库拉镜像AI牛牛31 分钟前
短剧内容自动化生产:知漫剧工作室落地教程
大数据·服务器·前端·人工智能·语音识别
律宏阔33 分钟前
Flutter 列表图片内存优化:CachedNetworkImage 与 ClipRRect 的取舍
前端·flutter
行者全栈架构师34 分钟前
【鸿蒙心迹】相册文搜图工程化落地:HarmonyOS 7.0 端侧 AI 检索全链路实战与 5 个踩坑解法
前端
律宏阔43 分钟前
Dart 3 Record:解决 Future.wait 异构返回值的类型问题
前端·flutter
Seraphina361 小时前
DVWA(XSS Reflected/Stored High,CSRF Low)
前端·xss·csrf
默_笙2 小时前
🍔 中间件不只是打日志:四个钩子、一次短路,和自带的工具
前端·javascript
程序员老赵2 小时前
Docker 部署 Dolibarr:轻松搭建开源 ERP/CRM 平台
运维·前端·后端
星禾元亨3 小时前
同一件事有三份资料,AI 该信哪一份?冲突判定、优先级链与处置流程
前端·人工智能
Dovis(誓平步青云)3 小时前
家里设备越来越多,如何用一张空间地图控制灯光和温度![
android·java·前端·javascript·人工智能·电脑