typeof对原始类型返回小写字符串(如"string"),对包装对象统一返回"object";区分二者需用instanceof或Object(x)!==x,因装箱机制使原始值方法调用透明但包装对象易致逻辑错误。

在 JavaScript 中,typeof 对原始类型(如字符串、数字、布尔值)和其对应的包装对象(String、Number、Boolean 构造函数创建的对象)返回不同的结果,这是容易混淆但有明确规则的行为。
原始类型始终返回小写类型名
所有原始类型的 typeof 结果都是小写的字符串:
-
typeof "hello"→"string" -
typeof 42→"number" -
typeof true→"boolean" -
typeof null→"object"(历史遗留 bug,但已成标准) -
typeof undefined→"undefined" -
typeof Symbol()→"symbol" -
typeof 10n→"bigint"
包装对象一律返回 "object"
用 new 调用包装构造函数生成的是普通对象,因此 typeof 统一返回 "object":
-
typeof new String("hello")→"object" -
typeof new Number(42)→"object" -
typeof new Boolean(true)→"object"
注意:即使该对象在逻辑上“代表”一个原始值,它仍是引用类型,具有自己的属性和原型链。
立即学习“Java免费学习笔记(深入)”;
区分原始值与包装对象的实用方法
仅靠 typeof 无法可靠区分 "abc" 和 new String("abc"),需结合其他判断:
- 用
Object.prototype.toString.call()获取更精确的内部标签:Object.prototype.toString.call("abc")→"[object String]"Object.prototype.toString.call(new String("abc"))→"[object String]"(结果相同,仍需进一步判断) - 检查是否为原始值:
typeof x === "string" && x.constructor === String不可靠;推荐用Object(x) !== x—— 原始值被Object()包装后会变成新对象,所以Object("a") !== "a"为true,而Object(new String("a")) === new String("a")为true。 - 最直接的方式是使用
value instanceof String—— 只对包装对象返回true,原始字符串返回false。
为什么设计如此?历史与实用性权衡
JavaScript 最初允许用 new String() 创建对象,以便给原始值临时附加方法(如 "abc".toUpperCase() 实际上是“装箱”为包装对象后调用)。但为了性能和语义清晰,引擎自动处理装箱/拆箱,开发者应优先使用原始类型。包装对象极少必要,且易引发意外行为(例如 new Boolean(false) 在布尔上下文中为 true)。


















