🔥 一文搞懂 JavaScript 包装类(面试必考)

0 阅读5分钟

🔥 一文搞懂 JavaScript 包装类(面试必考)

📌 一句话理解

包装类(Wrapper Objects) = JavaScript 为原始类型提供的临时对象包装,让原始值也能调用方法

// 原始类型(没有方法)
const str = 'hello';

// 但可以直接调用方法(自动装箱)
str.toUpperCase(); // 'HELLO'

// 本质:JavaScript 临时创建了 String 对象
new String('hello').toUpperCase(); // 'HELLO'

📋 目录

1. 什么是包装类
2. 5 种包装类详解
3. 自动装箱和拆箱
4. 常见陷阱
5. typeof vs instanceof
6. 面试高频题
7. 最佳实践

1️⃣ 什么是包装类?

原始类型 vs 对象类型

// 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(); // ✅ 可以调用!

包装类的作用

┌─────────────────────────────────────────────────────────────┐
│                    包装类工作原理                            │
├─────────────────────────────────────────────────────────────┤
│  1. 原始值 'hello'                                          │
│  2. 调用方法时 → 自动创建 String 对象(装箱)                 │
│  3. 执行方法                                                │
│  4. 销毁临时对象 → 返回原始值(拆箱)                         │
└─────────────────────────────────────────────────────────────┘

2️⃣ 5 种包装类详解

String 包装类

// 原始字符串
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 包装类

// 原始数字
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 包装类

// 原始布尔值
const bool = true;

// 可用的方法(很少)
bool.toString();      // 'true'
bool.valueOf();       // true

BigInt 包装类(ES2020)

// 大整数
const big = 123n;

// 可用的方法
big.toString();       // '123'
big.valueOf();        // 123n

Symbol 包装类(ES6)

// 符号
const sym = Symbol('key');

// 可用的方法
sym.toString();       // 'Symbol(key)'
sym.valueOf();        // Symbol(key)
sym.description;      // 'key'

3️⃣ 自动装箱和拆箱

装箱(Boxing)

// 原始值 → 对象
const str = 'hello';
const obj = new String(str);

// 自动装箱(调用方法时)
str.toUpperCase();
// 等价于
new String(str).toUpperCase();

拆箱(Unboxing)

// 对象 → 原始值
const obj = new String('hello');
const str = obj.valueOf(); // 'hello'
const str2 = obj.toString(); // 'hello'

// 自动拆箱(运算时)
const numObj = new Number(123);
numObj + 1; // 124(自动拆箱为原始值)

装箱拆箱流程图

┌─────────────────────────────────────────────────────────────┐
│                  自动装箱拆箱流程                            │
├─────────────────────────────────────────────────────────────┤
│                                                              │
│   原始值 'hello'                                             │
│       ↓                                                      │
│   调用方法 .toUpperCase()                                    │
│       ↓                                                      │
│   自动装箱 → new String('hello')                             │
│       ↓                                                      │
│   执行方法 → 'HELLO'                                         │
│       ↓                                                      │
│   自动拆箱 → 销毁临时对象                                     │
│       ↓                                                      │
│   返回结果 'HELLO'                                           │
│                                                              │
└─────────────────────────────────────────────────────────────┘

4️⃣ 常见陷阱 ⚠️

陷阱1:typeof 检测结果不同

const str1 = 'hello';
const str2 = new String('hello');

typeof str1; // 'string' ✅ 原始类型
typeof str2; // 'object' ❌ 对象类型

str1 === str2; // false(类型不同)
str1 == str2;  // true(值相等,自动拆箱)

陷阱2:对象永远为 truthy

const bool1 = false;
const bool2 = new Boolean(false);

if (bool1) {
    console.log('不会执行');
}

if (bool2) {
    console.log('会执行!❌'); // 对象永远为 true
}

// 正确做法
if (bool2.valueOf()) {
    console.log('不会执行');
}

陷阱3:属性赋值无效

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 创建的字符串

const str1 = 'hello';
const str2 = new String('hello');

str1 === str1; // true
str2 === str2; // true
str1 === str2; // false(不同类型)

// 比较时
str1 == str2;  // true(自动拆箱)

陷阱5:数组的 typeof

const arr = [1, 2, 3];
typeof arr; // 'object' ❌ 不是 'array'

// 正确判断
Array.isArray(arr); // true

5️⃣ typeof vs instanceof

typeof 操作符

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 操作符

'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

万能类型检测

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:输出什么?

const s1 = 'hello';
const s2 = new String('hello');

console.log(typeof s1);
console.log(typeof s2);
console.log(s1 === s2);
'string'
'object'
false

题2:输出什么?

const str = 'hello';
str.name = 'test';
console.log(str.name);
undefined
// 原因:临时对象被销毁,属性丢失

题3:输出什么?

const bool = new Boolean(false);
if (bool) {
    console.log('true');
} else {
    console.log('false');
}
'true'
// 原因:对象永远为 truthy,即使是 new Boolean(false)

题4:如何正确判断类型?

// 答案
const arr = [1, 2, 3];

// ❌ 错误
typeof arr === 'array';

// ✅ 正确
Array.isArray(arr);
Object.prototype.toString.call(arr) === '[object Array]';

题5:手写类型检测函数

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️⃣ 最佳实践

✅ 推荐使用原始类型

// ✅ 推荐
const str = 'hello';
const num = 123;
const bool = true;

// ❌ 避免
const str = new String('hello');
const num = new Number(123);
const bool = new Boolean(true);

✅ 类型转换

// 转字符串
String(123);      // '123'
(123).toString(); // '123'

// 转数字
Number('123');    // 123
+'123';           // 123
parseInt('123');  // 123

// 转布尔
Boolean('');      // false
!!'hello';        // true

✅ 类型检测

// 检测字符串
typeof str === 'string';

// 检测数组
Array.isArray(arr);

// 检测 null
value === null;

// 通用检测
Object.prototype.toString.call(value);

📊 包装类速查表

原始类型包装类创建方式常用方法
stringStringnew String('')toUpperCase(), slice(), split()
numberNumbernew Number(0)toString(), toFixed(), toPrecision()
booleanBooleannew Boolean(false)toString(), valueOf()
bigintBigIntnew BigInt(123n)toString(), valueOf()
symbolSymbolSymbol('key')toString(), valueOf(), description

🎯 总结

┌─────────────────────────────────────────────────────────────┐
│                    包装类核心要点                            │
├─────────────────────────────────────────────────────────────┤
│  1. 包装类让原始类型可以调用方法(自动装箱)                  │
│  2. 5 种包装类:StringNumberBooleanBigIntSymbol       │
│  3. typeof 检测原始类型,instanceof 检测对象类型              │
│  4. 避免使用 new String/Number/Boolean 创建值                │
│  5. 对象永远为 truthy(包括 new Boolean(false))             │
│  6. 临时对象的属性赋值会丢失                                 │
│  7. 万能类型检测:Object.prototype.toString.call()           │
└─────────────────────────────────────────────────────────────┘

记住口诀原始类型包装类,调用方法自动装;typeof 检测原始值,instanceof 检测对象;new 创建是对象,原始值才最推荐!


觉得有用?请点赞 + 收藏,下期预告:《JavaScript 类型转换详解:隐式转换的 10 个坑》 🚀