crush
将嵌套对象扁平化为单层对象,使用点号分隔的键名。
基础用法
typescript
import { crush } from 'radash'
const nested = {
user: {
profile: {
name: 'Alice',
age: 25
},
settings: {
theme: 'dark'
}
}
}
const flattened = crush(nested)
console.log(flattened)
// {
// 'user.profile.name': 'Alice',
// 'user.profile.age': 25,
// 'user.settings.theme': 'dark'
// }
语法
typescript
function crush<T extends Record<string, any>>(obj: T): Record<string, any>
参数
obj
(T): 要扁平化的嵌套对象
返回值
返回扁平化的对象,所有嵌套属性都使用点号分隔的键名。
示例
基本扁平化
typescript
import { crush } from 'radash'
const obj = {
name: 'Alice',
address: {
city: 'Beijing',
country: 'China'
}
}
const result = crush(obj)
console.log(result)
// {
// name: 'Alice',
// 'address.city': 'Beijing',
// 'address.country': 'China'
// }
处理深层嵌套
typescript
import { crush } from 'radash'
const deepNested = {
user: {
profile: {
personal: {
name: 'Alice',
age: 25,
contact: {
email: 'alice@example.com',
phone: '123-456-7890'
}
},
preferences: {
theme: 'dark',
language: 'en'
}
},
settings: {
notifications: {
email: true,
push: false
}
}
}
}
const result = crush(deepNested)
console.log(result)
// {
// 'user.profile.personal.name': 'Alice',
// 'user.profile.personal.age': 25,
// 'user.profile.personal.contact.email': 'alice@example.com',
// 'user.profile.personal.contact.phone': '123-456-7890',
// 'user.profile.preferences.theme': 'dark',
// 'user.profile.preferences.language': 'en',
// 'user.settings.notifications.email': true,
// 'user.settings.notifications.push': false
// }
处理数组
typescript
import { crush } from 'radash'
const objWithArrays = {
user: {
name: 'Alice',
hobbies: ['reading', 'swimming'],
skills: [
{ name: 'JavaScript', level: 'expert' },
{ name: 'TypeScript', level: 'intermediate' }
]
}
}
const result = crush(objWithArrays)
console.log(result)
// {
// 'user.name': 'Alice',
// 'user.hobbies.0': 'reading',
// 'user.hobbies.1': 'swimming',
// 'user.skills.0.name': 'JavaScript',
// 'user.skills.0.level': 'expert',
// 'user.skills.1.name': 'TypeScript',
// 'user.skills.1.level': 'intermediate'
// }
处理混合数据类型
typescript
import { crush } from 'radash'
const mixedData = {
user: {
name: 'Alice',
age: 25,
isActive: true,
score: 95.5,
tags: ['admin', 'premium'],
metadata: {
createdAt: new Date('2023-01-01'),
lastLogin: new Date('2023-12-31')
}
}
}
const result = crush(mixedData)
console.log(result)
// {
// 'user.name': 'Alice',
// 'user.age': 25,
// 'user.isActive': true,
// 'user.score': 95.5,
// 'user.tags.0': 'admin',
// 'user.tags.1': 'premium',
// 'user.metadata.createdAt': 2023-01-01T00:00:00.000Z,
// 'user.metadata.lastLogin': 2023-12-31T00:00:00.000Z
// }
处理空值和undefined
typescript
import { crush } from 'radash'
const objWithNulls = {
user: {
name: 'Alice',
email: null,
phone: undefined,
address: {
city: 'Beijing',
zipCode: null
}
}
}
const result = crush(objWithNulls)
console.log(result)
// {
// 'user.name': 'Alice',
// 'user.email': null,
// 'user.phone': undefined,
// 'user.address.city': 'Beijing',
// 'user.address.zipCode': null
// }
处理函数和对象
typescript
import { crush } from 'radash'
const objWithFunctions = {
user: {
name: 'Alice',
greet: () => 'Hello!',
config: {
handler: function() { return 'config' },
data: { id: 1 }
}
}
}
const result = crush(objWithFunctions)
console.log(result)
// {
// 'user.name': 'Alice',
// 'user.greet': [Function: greet],
// 'user.config.handler': [Function: handler],
// 'user.config.data.id': 1
// }
处理复杂配置对象
typescript
import { crush } from 'radash'
const config = {
server: {
host: 'localhost',
port: 3000,
cors: {
origin: ['http://localhost:3000', 'https://example.com'],
credentials: true
}
},
database: {
url: 'postgresql://localhost:5432/mydb',
pool: {
min: 1,
max: 10
}
},
api: {
version: 'v1',
rateLimit: {
windowMs: 15 * 60 * 1000,
max: 100
}
}
}
const result = crush(config)
console.log(result)
// {
// 'server.host': 'localhost',
// 'server.port': 3000,
// 'server.cors.origin.0': 'http://localhost:3000',
// 'server.cors.origin.1': 'https://example.com',
// 'server.cors.credentials': true,
// 'database.url': 'postgresql://localhost:5432/mydb',
// 'database.pool.min': 1,
// 'database.pool.max': 10,
// 'api.version': 'v1',
// 'api.rateLimit.windowMs': 900000,
// 'api.rateLimit.max': 100
// }
处理API响应数据
typescript
import { crush } from 'radash'
const apiResponse = {
status: 200,
data: {
user: {
id: 1,
name: 'Alice',
profile: {
avatar: 'https://example.com/avatar.jpg',
bio: 'Software Developer'
},
posts: [
{ id: 1, title: 'First Post', content: 'Hello World' },
{ id: 2, title: 'Second Post', content: 'Another post' }
]
}
},
meta: {
timestamp: new Date(),
requestId: 'req_123456'
}
}
const result = crush(apiResponse)
console.log(result)
// {
// status: 200,
// 'data.user.id': 1,
// 'data.user.name': 'Alice',
// 'data.user.profile.avatar': 'https://example.com/avatar.jpg',
// 'data.user.profile.bio': 'Software Developer',
// 'data.user.posts.0.id': 1,
// 'data.user.posts.0.title': 'First Post',
// 'data.user.posts.0.content': 'Hello World',
// 'data.user.posts.1.id': 2,
// 'data.user.posts.1.title': 'Second Post',
// 'data.user.posts.1.content': 'Another post',
// 'meta.timestamp': 2023-12-31T12:00:00.000Z,
// 'meta.requestId': 'req_123456'
// }
处理表单数据
typescript
import { crush } from 'radash'
const formData = {
personal: {
firstName: 'Alice',
lastName: 'Smith',
email: 'alice@example.com'
},
address: {
street: '123 Main St',
city: 'Beijing',
country: 'China',
zipCode: '100000'
},
preferences: {
newsletter: true,
notifications: {
email: true,
sms: false,
push: true
}
}
}
const result = crush(formData)
console.log(result)
// {
// 'personal.firstName': 'Alice',
// 'personal.lastName': 'Smith',
// 'personal.email': 'alice@example.com',
// 'address.street': '123 Main St',
// 'address.city': 'Beijing',
// 'address.country': 'China',
// 'address.zipCode': '100000',
// 'preferences.newsletter': true,
// 'preferences.notifications.email': true,
// 'preferences.notifications.sms': false,
// 'preferences.notifications.push': true
// }
处理嵌套对象数组
typescript
import { crush } from 'radash'
const complexData = {
users: [
{
id: 1,
name: 'Alice',
roles: ['admin', 'user'],
profile: {
age: 25,
skills: ['JavaScript', 'TypeScript']
}
},
{
id: 2,
name: 'Bob',
roles: ['user'],
profile: {
age: 30,
skills: ['Python', 'Java']
}
}
],
settings: {
theme: 'dark',
features: {
advanced: true,
beta: false
}
}
}
const result = crush(complexData)
console.log(result)
// {
// 'users.0.id': 1,
// 'users.0.name': 'Alice',
// 'users.0.roles.0': 'admin',
// 'users.0.roles.1': 'user',
// 'users.0.profile.age': 25,
// 'users.0.profile.skills.0': 'JavaScript',
// 'users.0.profile.skills.1': 'TypeScript',
// 'users.1.id': 2,
// 'users.1.name': 'Bob',
// 'users.1.roles.0': 'user',
// 'users.1.profile.age': 30,
// 'users.1.profile.skills.0': 'Python',
// 'users.1.profile.skills.1': 'Java',
// 'settings.theme': 'dark',
// 'settings.features.advanced': true,
// 'settings.features.beta': false
// }
处理数据库查询结果
typescript
import { crush } from 'radash'
const dbResult = {
id: 1,
name: 'Product A',
category: {
id: 5,
name: 'Electronics',
parent: {
id: 1,
name: 'Technology'
}
},
variants: [
{
id: 101,
color: 'Red',
price: 99.99,
stock: {
quantity: 50,
location: 'Warehouse A'
}
},
{
id: 102,
color: 'Blue',
price: 89.99,
stock: {
quantity: 30,
location: 'Warehouse B'
}
}
]
}
const result = crush(dbResult)
console.log(result)
// {
// id: 1,
// name: 'Product A',
// 'category.id': 5,
// 'category.name': 'Electronics',
// 'category.parent.id': 1,
// 'category.parent.name': 'Technology',
// 'variants.0.id': 101,
// 'variants.0.color': 'Red',
// 'variants.0.price': 99.99,
// 'variants.0.stock.quantity': 50,
// 'variants.0.stock.location': 'Warehouse A',
// 'variants.1.id': 102,
// 'variants.1.color': 'Blue',
// 'variants.1.price': 89.99,
// 'variants.1.stock.quantity': 30,
// 'variants.1.stock.location': 'Warehouse B'
// }
处理错误对象
typescript
import { crush } from 'radash'
const errorObject = {
name: 'ValidationError',
message: 'Invalid input',
details: {
field: 'email',
value: 'invalid-email',
constraints: {
format: 'Must be a valid email',
required: 'Email is required'
}
},
stack: 'Error: Invalid input\n at validate...'
}
const result = crush(errorObject)
console.log(result)
// {
// name: 'ValidationError',
// message: 'Invalid input',
// 'details.field': 'email',
// 'details.value': 'invalid-email',
// 'details.constraints.format': 'Must be a valid email',
// 'details.constraints.required': 'Email is required',
// stack: 'Error: Invalid input\n at validate...'
// }
处理日志数据
typescript
import { crush } from 'radash'
const logEntry = {
timestamp: new Date(),
level: 'ERROR',
message: 'Database connection failed',
context: {
userId: 123,
requestId: 'req_456',
metadata: {
ip: '192.168.1.1',
userAgent: 'Mozilla/5.0...'
}
},
error: {
code: 'ECONNREFUSED',
message: 'Connection refused',
stack: 'Error: Connection refused...'
}
}
const result = crush(logEntry)
console.log(result)
// {
// timestamp: 2023-12-31T12:00:00.000Z,
// level: 'ERROR',
// message: 'Database connection failed',
// 'context.userId': 123,
// 'context.requestId': 'req_456',
// 'context.metadata.ip': '192.168.1.1',
// 'context.metadata.userAgent': 'Mozilla/5.0...',
// 'error.code': 'ECONNREFUSED',
// 'error.message': 'Connection refused',
// 'error.stack': 'Error: Connection refused...'
// }
处理空对象和边界情况
typescript
import { crush } from 'radash'
// 空对象
console.log(crush({})) // {}
// 只有顶层属性
console.log(crush({ a: 1, b: 2 })) // { a: 1, b: 2 }
// 包含空对象
console.log(crush({ a: 1, b: {}, c: 3 })) // { a: 1, b: {}, c: 3 }
// 包含空数组
console.log(crush({ a: 1, b: [], c: 3 })) // { a: 1, b: [], c: 3 }
// 包含null和undefined
console.log(crush({ a: 1, b: null, c: undefined })) // { a: 1, b: null, c: undefined }
注意事项
- 数组索引: 数组元素使用数字索引,如
array.0
,array.1
- 嵌套层级: 支持任意深度的嵌套对象
- 数据类型: 保持原始数据类型,包括null、undefined、函数等
- 循环引用: 不处理循环引用,可能导致无限递归
- 性能: 对于大型嵌套对象,扁平化操作可能较慢
与其他方法的区别
Object.assign()
: 浅合并对象crush()
: 将嵌套对象完全扁平化flatten()
: 通常用于数组扁平化pick()
: 选择特定属性omit()
: 排除特定属性
实际应用场景
- 数据库查询: 将嵌套查询结果扁平化
- API响应: 处理复杂的API响应数据
- 表单处理: 扁平化表单数据结构
- 配置管理: 处理嵌套的配置对象
- 日志分析: 扁平化日志数据结构