Skip to content

Commit

Permalink
feat: 新增深拷贝deepCopy方法 (#44)
Browse files Browse the repository at this point in the history
* feat: 新增深拷贝方法

* feat: 扩展deepCopy的功能,增加TS类型重构提示

* feat: 调整deepCopy测试用例

* feat: 修复数组和对象的循环引用

* feat: 增加deepCopy循环引用的单测

* fix: 修复对象创建的数组和数组实例不一致的问题

---------

Co-authored-by: 李苏晨 <lisuchen@uupaotui.com>
Co-authored-by: VictorBo <hi@vtrbo.cn>
  • Loading branch information
3 people committed Jun 21, 2024
1 parent fcad291 commit be61573
Show file tree
Hide file tree
Showing 10 changed files with 1,086 additions and 511 deletions.
6 changes: 1 addition & 5 deletions eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,7 @@ import defineConfig from '@antfu/eslint-config'

export default defineConfig(
{
formatters: {
css: true,
html: true,
markdown: 'prettier',
},
formatters: true,
},
{
files: ['examples/*/*.*'],
Expand Down
1 change: 1 addition & 0 deletions packages/core/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from '@xparcai-utils/tool'
export * from '@xparcai-utils/is'
export * from '@xparcai-utils/string'
export * from '@xparcai-utils/object'
1 change: 1 addition & 0 deletions packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
},
"dependencies": {
"@xparcai-utils/is": "workspace:*",
"@xparcai-utils/object": "workspace:*",
"@xparcai-utils/string": "workspace:*",
"@xparcai-utils/tool": "workspace:*"
}
Expand Down
49 changes: 49 additions & 0 deletions packages/object/__test__/deepCopy.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { describe, expect, it } from 'vitest'
import { deepCopy } from '..'

describe('@xparcai-utils/object', () => {
it('deepCopy: 复制基本类型', () => {
let data: any = 666
expect(deepCopy(data)).toBe(data)
data = 'xparcai'
expect(deepCopy(data)).toBe(data)
data = false
expect(deepCopy(data)).toBe(data)
data = null
expect(deepCopy(data)).toBeNull()
data = undefined
expect(deepCopy(data)).toBeUndefined()
})

it('deepCopy: 复制数组', () => {
const data: any = ['0.0.1', '0.0.2']
expect(deepCopy(data)).toEqual(data)
expect(deepCopy(data)).not.toBe(data)
data.push(data)
expect(deepCopy(data)).toEqual(data)
expect(deepCopy(data)).not.toBe(data)
expect(deepCopy(data)[2]).toEqual(data[2])
})

it('deepCopy: 复制对象', () => {
const data: any = {
name: 'xparcai',
regexp: new RegExp('xparcai'),
version: 1,
}
expect(deepCopy(data)).toEqual(data)
expect(deepCopy(data)).not.toBe(data)
data.data = data
expect(deepCopy(data)).toEqual(data)
expect(deepCopy(data)).not.toBe(data)
expect(deepCopy(data).data).toEqual(data.data)
})

it('deepCopy: 复制函数', () => {
let data: any = function () {}
expect(deepCopy(data)).toBe(data)
data = () => {}
expect(deepCopy(data)).toBe(data)
// ......
})
})
1 change: 1 addition & 0 deletions packages/object/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './src/deepCopy'
57 changes: 57 additions & 0 deletions packages/object/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
{
"name": "@xparcai-utils/object",
"type": "module",
"version": "0.0.0",
"description": "🍒 Collection of common JavaScript or TypeScript utils.",
"author": {
"name": "VictorBo",
"email": "hi@vtrbo.cn",
"github": "https://github.com/vtrbo"
},
"license": "MIT",
"homepage": "https://github.com/xparcai/xparcai-utils",
"bugs": "https://github.com/xparcai/xparcai-utils/issues",
"keywords": [
"pnpm",
"monorepo",
"javascript",
"typescript",
"vue",
"react",
"angular",
"svelte",
"utils",
"tools"
],
"publishConfig": {
"access": "public"
},
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.mjs",
"require": "./dist/index.cjs",
"browser": "./dist/index.js"
}
},
"main": "dist/index.cjs",
"module": "dist/index.mjs",
"browser": "dist/index.js",
"typings": "dist/index.d.ts",
"files": [
"README.md",
"dist"
],
"scripts": {
"dev": "pnpm run build -w",
"build": "rollup -c rollup.config.ts --configPlugin typescript2",
"lint": "eslint .",
"test": "vitest",
"clean": "run-s clean:*",
"clean:dist": "rimraf dist",
"clean:deps": "rimraf node_modules"
},
"devDependencies": {
"@xparcai-utils/is": "workspace:*"
}
}
6 changes: 6 additions & 0 deletions packages/object/rollup.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { defineConfig } from 'rollup'
import { resolveRollupConfig } from '../../scripts/rollup-config'

const rollupConfig = resolveRollupConfig('xparcai-utils')

export default defineConfig(rollupConfig)
47 changes: 47 additions & 0 deletions packages/object/src/deepCopy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { isArray, isDate, isObject, isRegExp } from '@xparcai-utils/is'

/**
* @func deepCopy
* @param {T} data 将要复制的对象
* @returns {T} 复制后的对象
* @desc 深拷贝对象
*/
export function deepCopy<T>(data: T): T
/**
* @func deepCopy
* @param {T} data 将要复制的对象
* @param {H extends object} [hash] 记录已复制过对象的哈希值
* @returns {T} 复制后的对象
* @desc 深拷贝对象
*/
export function deepCopy<T, H extends object>(data: T, hash?: H): T
export function deepCopy<T>(data: T, hash: any = new WeakMap()): T {
// 日期对象直接返回一个新的日期对象
if (isDate(data)) {
return new Date(data) as T
}
// 正则对象直接返回一个新的正则对象
if (isRegExp(data)) {
return new RegExp(data) as T
}
// 数组和对象
if (isArray(data) || isObject(data)) {
// 如果循环引用,就用 weakMap 来解决
if (hash.has(data)) {
return hash.get(data)
}
const _data: any = isArray(data) ? [] : {}
hash.set(data, _data)
for (const key of Reflect.ownKeys(data as object)) {
if (isObject((data as any)[key])) {
_data[key] = deepCopy((data as any)[key], hash)
}
else {
_data[key] = (data as any)[key]
}
}
return _data
}
// 基本数据类型
return data
}
3 changes: 3 additions & 0 deletions packages/object/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"extends": "../../tsconfig.json"
}
Loading

0 comments on commit be61573

Please sign in to comment.