🔥 一文搞懂 JavaScript 包装类(面试必考)
📌 一句话理解
包装类(Wrapper Objects) = JavaScript 为原始类型 提供的临时对象包装,让原始值也能调用方法
javascript
// 原始类型(没有方法)
const str = 'hello';
// 但可以直接调用方法(自动装箱)
str.toUpperCase(); // 'HELLO'
// 本质:JavaScript 临时创建了 String 对象
new String('hello').toUpperCase(); // 'HELLO'
📋 目录
markdown
1. 什么是包装类
2. 5 种包装类详解
3. 自动装箱和拆箱
4. 常见陷阱
5. typeof vs instanceof
6. 面试高频题
7. 最佳实践
1️⃣ 什么是包装类?
原始类型 vs 对象类型
javascript
// 6 种原始类型(Primitive Types)
typeof 'hello' // 'string'
typeof 123 // 'number'
typeof true // 'boolean'
typeof null // 'object' (历史遗留 bug)
typeof undefined // 'undefined'
typeof Symbol() // 'symbol'
typeof 123n // 'bigint'
// 原始类型没有方法,但...
'hello'.toUpperCase(); // ✅ 可以调用!
包装类的作用
arduino
┌─────────────────────────────────────────────────────────────┐
│ 包装类工作原理 │
├─────────────────────────────────────────────────────────────┤
│ 1. 原始值 'hello' │
│ 2. 调用方法时 → 自动创建 String 对象(装箱) │
│ 3. 执行方法 │
│ 4. 销毁临时对象 → 返回原始值(拆箱) │
└─────────────────────────────────────────────────────────────┘
2️⃣ 5 种包装类详解
String 包装类
javascript
// 原始字符串
const str = 'hello';
// 自动装箱(临时创建 String 对象)
const tempObj = new String('hello');
// 可用的方法
str.length; // 5
str.toUpperCase(); // 'HELLO'
str.toLowerCase(); // 'hello'
str.slice(0, 3); // 'hel'
str.split(''); // ['h', 'e', 'l', 'l', 'o']
str.trim(); // 去除空格
str.includes('ell'); // true
str.replace('h', 'H'); // 'Hello'
Number 包装类
javascript
// 原始数字
const num = 123;
// 可用的方法
num.toString(); // '123'
num.toFixed(2); // '123.00'
num.toPrecision(5); // '123.00'
Number.isNaN(num); // false
Number.isFinite(num); // true
// 特殊值
NaN.toString(); // 'NaN'
Infinity.toString(); // 'Infinity'
Boolean 包装类
javascript
// 原始布尔值
const bool = true;
// 可用的方法(很少)
bool.toString(); // 'true'
bool.valueOf(); // true
BigInt 包装类(ES2020)
javascript
// 大整数
const big = 123n;
// 可用的方法
big.toString(); // '123'
big.valueOf(); // 123n
Symbol 包装类(ES6)
javascript
// 符号
const sym = Symbol('key');
// 可用的方法
sym.toString(); // 'Symbol(key)'
sym.valueOf(); // Symbol(key)
sym.description; // 'key'
3️⃣ 自动装箱和拆箱
装箱(Boxing)
javascript
// 原始值 → 对象
const str = 'hello';
const obj = new String(str);
// 自动装箱(调用方法时)
str.toUpperCase();
// 等价于
new String(str).toUpperCase();
拆箱(Unboxing)
javascript
// 对象 → 原始值
const obj = new String('hello');
const str = obj.valueOf(); // 'hello'
const str2 = obj.toString(); // 'hello'
// 自动拆箱(运算时)
const numObj = new Number(123);
numObj + 1; // 124(自动拆箱为原始值)
装箱拆箱流程图
javascript
┌─────────────────────────────────────────────────────────────┐
│ 自动装箱拆箱流程 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 原始值 'hello' │
│ ↓ │
│ 调用方法 .toUpperCase() │
│ ↓ │
│ 自动装箱 → new String('hello') │
│ ↓ │
│ 执行方法 → 'HELLO' │
│ ↓ │
│ 自动拆箱 → 销毁临时对象 │
│ ↓ │
│ 返回结果 'HELLO' │
│ │
└─────────────────────────────────────────────────────────────┘
4️⃣ 常见陷阱 ⚠️
陷阱1:typeof 检测结果不同
javascript
const str1 = 'hello';
const str2 = new String('hello');
typeof str1; // 'string' ✅ 原始类型
typeof str2; // 'object' ❌ 对象类型
str1 === str2; // false(类型不同)
str1 == str2; // true(值相等,自动拆箱)
陷阱2:对象永远为 truthy
javascript
const bool1 = false;
const bool2 = new Boolean(false);
if (bool1) {
console.log('不会执行');
}
if (bool2) {
console.log('会执行!❌'); // 对象永远为 true
}
// 正确做法
if (bool2.valueOf()) {
console.log('不会执行');
}
陷阱3:属性赋值无效
javascript
const str = 'hello';
str.customProp = 'test'; // ❌ 临时对象,赋值后立即销毁
console.log(str.customProp); // undefined
// 正确做法(使用对象)
const strObj = new String('hello');
strObj.customProp = 'test';
console.log(strObj.customProp); // 'test'
陷阱4:new String 创建的字符串
javascript
const str1 = 'hello';
const str2 = new String('hello');
str1 === str1; // true
str2 === str2; // true
str1 === str2; // false(不同类型)
// 比较时
str1 == str2; // true(自动拆箱)
陷阱5:数组的 typeof
javascript
const arr = [1, 2, 3];
typeof arr; // 'object' ❌ 不是 'array'
// 正确判断
Array.isArray(arr); // true
5️⃣ typeof vs instanceof
typeof 操作符
javascript
typeof 'hello' // 'string'
typeof 123 // 'number'
typeof true // 'boolean'
typeof undefined // 'undefined'
typeof Symbol() // 'symbol'
typeof 123n // 'bigint'
typeof null // 'object' ❌ 历史 bug
typeof {} // 'object'
typeof [] // 'object' ❌
typeof function(){} // 'function'
instanceof 操作符
javascript
'hello' instanceof String; // false(原始类型)
new String('hello') instanceof String; // true
123 instanceof Number; // false
new Number(123) instanceof Number; // true
[] instanceof Array; // true
{} instanceof Object; // true
对比表
| 操作符 | 检测原始类型 | 检测对象类型 | 检测数组 | 检测 null |
|---|---|---|---|---|
typeof |
✅ | ❌(都是 object) | ❌ | ❌(返回 object) |
instanceof |
❌ | ✅ | ✅ | ❌ |
Array.isArray() |
❌ | ❌ | ✅ | ❌ |
Object.prototype.toString |
✅ | ✅ | ✅ | ✅ |
万能类型检测
javascript
function getType(value) {
return Object.prototype.toString.call(value).slice(8, -1);
}
getType('hello'); // 'String'
getType(123); // 'Number'
getType(true); // 'Boolean'
getType(null); // 'Null'
getType(undefined); // 'Undefined'
getType([]); // 'Array'
getType({}); // 'Object'
getType(function(){});// 'Function'
getType(new Date()); // 'Date'
6️⃣ 面试高频题
题1:输出什么?
javascript
const s1 = 'hello';
const s2 = new String('hello');
console.log(typeof s1);
console.log(typeof s2);
console.log(s1 === s2);
arduino
'string'
'object'
false
题2:输出什么?
javascript
const str = 'hello';
str.name = 'test';
console.log(str.name);
javascript
undefined
// 原因:临时对象被销毁,属性丢失
题3:输出什么?
javascript
const bool = new Boolean(false);
if (bool) {
console.log('true');
} else {
console.log('false');
}
sql
'true'
// 原因:对象永远为 truthy,即使是 new Boolean(false)
题4:如何正确判断类型?
javascript
// 答案
const arr = [1, 2, 3];
// ❌ 错误
typeof arr === 'array';
// ✅ 正确
Array.isArray(arr);
Object.prototype.toString.call(arr) === '[object Array]';
题5:手写类型检测函数
javascript
function getType(value) {
if (value === null) return 'null';
if (value === undefined) return 'undefined';
return Object.prototype.toString.call(value).slice(8, -1);
}
// 测试
getType(null); // 'null'
getType([]); // 'Array'
getType(new Date()); // 'Date'
getType(/regex/); // 'RegExp'
7️⃣ 最佳实践
✅ 推荐使用原始类型
javascript
// ✅ 推荐
const str = 'hello';
const num = 123;
const bool = true;
// ❌ 避免
const str = new String('hello');
const num = new Number(123);
const bool = new Boolean(true);
✅ 类型转换
javascript
// 转字符串
String(123); // '123'
(123).toString(); // '123'
// 转数字
Number('123'); // 123
+'123'; // 123
parseInt('123'); // 123
// 转布尔
Boolean(''); // false
!!'hello'; // true
✅ 类型检测
javascript
// 检测字符串
typeof str === 'string';
// 检测数组
Array.isArray(arr);
// 检测 null
value === null;
// 通用检测
Object.prototype.toString.call(value);
📊 包装类速查表
| 原始类型 | 包装类 | 创建方式 | 常用方法 |
|---|---|---|---|
| string | String | new String('') |
toUpperCase(), slice(), split() |
| number | Number | new Number(0) |
toString(), toFixed(), toPrecision() |
| boolean | Boolean | new Boolean(false) |
toString(), valueOf() |
| bigint | BigInt | new BigInt(123n) |
toString(), valueOf() |
| symbol | Symbol | Symbol('key') |
toString(), valueOf(), description |
🎯 总结
javascript
┌─────────────────────────────────────────────────────────────┐
│ 包装类核心要点 │
├─────────────────────────────────────────────────────────────┤
│ 1. 包装类让原始类型可以调用方法(自动装箱) │
│ 2. 5 种包装类:String、Number、Boolean、BigInt、Symbol │
│ 3. typeof 检测原始类型,instanceof 检测对象类型 │
│ 4. 避免使用 new String/Number/Boolean 创建值 │
│ 5. 对象永远为 truthy(包括 new Boolean(false)) │
│ 6. 临时对象的属性赋值会丢失 │
│ 7. 万能类型检测:Object.prototype.toString.call() │
└─────────────────────────────────────────────────────────────┘
记住口诀 :原始类型包装类,调用方法自动装;typeof 检测原始值,instanceof 检测对象;new 创建是对象,原始值才最推荐!
觉得有用?请点赞 + 收藏,下期预告:《JavaScript 类型转换详解:隐式转换的 10 个坑》 🚀