你是谁,对象?在 TypeScript 中获取类名(运行时)

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

为什么你需要在运行时获取类名?

\n\n

想象一下:你正在用 TypeScript 编写一个复杂的系统。你有一个类的层次结构——User、Admin、Moderator。在代码的某个深处,你获取到一个对象,但不知道它到底是什么。你在控制台中只看到 object。

\n\n

或者,你正在构建一个日志记录器,它不应该只输出 [Object],而应该输出有意义的类名:[User: John]。又或者,你正在编写一个装饰器,它需要根据对象的类型来决定如何处理它。

\n\n

这时,Stack Overflow 上那个有上千次浏览的问题就派上用场了:"在运行时获取对象的类名"。今天,我们不仅会给出答案,还会深入 TypeScript 和 JavaScript 的底层,了解其真正的工作原理。

\n\n

是的,TypeScript 是 JavaScript 的超集。所有类型的魔法在编译后都会消失。但类名不是类型,它是原型的一个属性。它在运行时仍然存在。

\n\n

最简单的方法:constructor.name

\n\n

如果你曾经搜索过这个问题,你很可能见过这个一行代码:

\n\n
class User {\n  constructor(public name: string) {}\n}\n\nconst user = new User("Alice");\nconsole.log(user.constructor.name); // "User"
\n\n

有效吗?是的。快吗?是的。但如果你不了解其内部机制,有一些细节可能会让你措手不及。

\n\n

底层是如何工作的?

\n\n

JavaScript 中的每个对象都有一个 constructor 属性。它是对创建该对象的函数的引用。而每个函数(类也是函数)都有一个 name 属性。

\n\n

当你写 user.constructor.name 时,引擎会执行以下操作:

\n
    \n
  • 沿着 user 对象的原型链向上查找。
  • \n
  • 在 User.prototype 上找到 constructor 属性。
  • \n
  • 读取构造函数 User 的 name 属性。
  • \n
\n\n

这是一个开销很小的操作,但并非完全没有成本。在大多数情况下,你甚至不会注意到它。

\n\n

什么时候 constructor.name 会失效?

\n\n

这是一个经典的陷阱:

\n\n
const obj = Object.create(null);\nconsole.log(obj.constructor); // undefined\n// console.log(obj.constructor.name); // TypeError!
\n\n

通过 Object.create(null) 创建的对象没有原型。它没有 constructor。请务必小心。

\n\n

第二种情况是代码压缩。如果你使用打包工具(如 Webpack、Terser)重命名了类,constructor.name 可能会返回类似 t 或 e 这样的值。这仅在生产环境中是问题,但值得了解。

\n\n

替代方案:instanceof 和自定义检查

\n\n

有时你需要的不仅仅是名称,而是一个检查:"这个对象是类 X 的实例吗?"

\n\n
class Animal {}\nclass Dog extends Animal {}\n\nconst dog = new Dog();\n\nconsole.log(dog instanceof Dog);    // true\nconsole.log(dog instanceof Animal); // true\nconsole.log(dog instanceof Object); // true
\n\n

instanceof 通过原型链工作。它检查 Dog.prototype 是否存在于 dog 对象的原型链中。如果是,则返回 true。

\n\n

但 instanceof 不会给你一个字符串名称。它只返回一个布尔值。对于日志记录或序列化来说,这并不适用。

\n\n

组合使用:检查 + 名称

\n\n

你可以编写一个工具函数,先检查类型,再返回名称:

\n\n
function getClassName(obj: any): string | null {\n  if (obj === null || obj === undefined) return null;\n  if (typeof obj !== 'object' && typeof obj !== 'function') return null;\n\n  // 防止 Object.create(null) 的情况\n  if (!obj.constructor) return 'Object (no prototype)';\n\n  const name                

博客

书籍推荐