diff --git a/.changeset/tasty-crabs-work.md b/.changeset/tasty-crabs-work.md
new file mode 100644
index 000000000..10ec8be36
--- /dev/null
+++ b/.changeset/tasty-crabs-work.md
@@ -0,0 +1,5 @@
+---
+'@modern-kit/utils': minor
+---
+
+fix(utils): deepCopy -> cloneDeep 네이밍 변경 및 기능 개선 - @ssi02014
diff --git a/docs/docs/utils/common/cloneDeep.md b/docs/docs/utils/common/cloneDeep.md
new file mode 100644
index 000000000..7e5023d1f
--- /dev/null
+++ b/docs/docs/utils/common/cloneDeep.md
@@ -0,0 +1,48 @@
+# cloneDeep
+
+인자로 주어진 값을 `깊은 복사`를 수행하는 함수입니다.
+
+
+
+## Code
+[🔗 실제 구현 코드 확인](https://github.com/modern-agile-team/modern-kit/blob/main/packages/utils/src/common/cloneDeep/index.ts)
+
+## Benchmark
+- `hz`: 초당 작업 수
+- `mean`: 평균 응답 시간(ms)
+
+|이름|hz|mean|성능|
+|------|---|---|---|
+|modern-kit/cloneDeep|1,529,157.20|0.0007|`fastest`|
+|lodash/cloneDeep|650,320.39|0.0015|-|
+
+- **modern-kit/cloneDeep**
+ - `2.35x` faster than lodash/cloneDeep
+
+## Interface
+```ts title="typescript"
+function cloneDeep(value: T): T
+```
+
+## Usage
+```ts title="typescript"
+import { cloneDeep } from '@modern-kit/utils';
+
+const originNum = 42;
+const copyNum = cloneDeep(originNum);
+
+const originObj = { a: 1, b: { c: 2 } };
+const copyObj = cloneDeep(originObj);
+
+const originArray = [1, 2, [3, 4]];
+const copyArray = cloneDeep(originArray);
+
+const originSet = new Set([1, 2, 3]);
+const copySet = cloneDeep(originSet);
+
+const originMap = new Map([
+ ['a', 1],
+ ['b', 2],
+]);
+const copyMap = cloneDeep(originMap);
+```
\ No newline at end of file
diff --git a/docs/docs/utils/common/deepCopy.md b/docs/docs/utils/common/deepCopy.md
deleted file mode 100644
index d9f3ce61b..000000000
--- a/docs/docs/utils/common/deepCopy.md
+++ /dev/null
@@ -1,36 +0,0 @@
-# deepCopy
-
-인자로 주어진 값을 `깊은 복사`를 수행하는 함수입니다.
-
-
-
-## Code
-[🔗 실제 구현 코드 확인](https://github.com/modern-agile-team/modern-kit/blob/main/packages/utils/src/common/deepCopy/index.ts)
-
-## Interface
-```ts title="typescript"
-const deepCopy: (value: T) => T
-```
-
-## Usage
-```ts title="typescript"
-import { deepCopy } from '@modern-kit/utils';
-
-const originNum = 42;
-const copyNum = deepCopy(originNum);
-
-const originObj = { a: 1, b: { c: 2 } };
-const copyObj = deepCopy(originObj);
-
-const originArray = [1, 2, [3, 4]];
-const copyArray = deepCopy(originArray);
-
-const originSet = new Set([1, 2, 3]);
-const copySet = deepCopy(originSet);
-
-const originMap = new Map([
- ['a', 1],
- ['b', 2],
-]);
-const copyMap = deepCopy(originMap);
-```
\ No newline at end of file
diff --git a/docs/docs/utils/object/omit.md b/docs/docs/utils/object/omit.md
index 28cdf16a9..2d69283f8 100644
--- a/docs/docs/utils/object/omit.md
+++ b/docs/docs/utils/object/omit.md
@@ -15,11 +15,11 @@
|이름|hz|mean|성능|
|------|---|---|---|
-|modern-kit/omit|3,567,312.89|0.0003|`fastest`|
-|lodash/omit|879,967.75|0.0011|-|
+|modern-kit/omit|1,505,400.16|0.0003|`fastest`|
+|lodash/omit|901,269.43|0.0011|-|
- **modern-kit/omit**
- - `4.05x` faster than lodash/omit
+ - `1.67x` faster than lodash/omit
## Interface
```ts title="typescript"
diff --git a/docs/docs/utils/object/pick.md b/docs/docs/utils/object/pick.md
index 3acb72300..758853ba5 100644
--- a/docs/docs/utils/object/pick.md
+++ b/docs/docs/utils/object/pick.md
@@ -2,8 +2,6 @@
인자로 넣은 `keys`로 구성된 객체를 반환하는 함수입니다. 반환된 객체는 `깊은 복사된 새로운 객체`입니다.
-`symbol`은 제외됩니다.
-
## Code
@@ -15,11 +13,11 @@
|이름|hz|mean|성능|
|------|---|---|---|
-|modern-kit/pick|5,663,602.36|0.0002|`fastest`|
-|lodash/pick|1,035,576.42|0.0010|-|
+|modern-kit/pick|1,693,028.73|0.0002|`fastest`|
+|lodash/pick|1,022,887.39|0.0010|-|
- **modern-kit/pick**
- - `4.05x` faster than lodash/pick
+ - `1.60x` faster than lodash/pick
## Interface
```ts title="typescript"
diff --git a/packages/utils/src/common/cloneDeep/cloneDeep.bench.ts b/packages/utils/src/common/cloneDeep/cloneDeep.bench.ts
new file mode 100644
index 000000000..7f9c1f792
--- /dev/null
+++ b/packages/utils/src/common/cloneDeep/cloneDeep.bench.ts
@@ -0,0 +1,13 @@
+import { bench, describe } from 'vitest';
+import { cloneDeep as cloneDeep } from '.';
+import { cloneDeep as cloneDeepLodash } from 'lodash-es';
+
+describe('cloneDeep', () => {
+ bench('@modern-kit/cloneDeep', () => {
+ cloneDeep({ a: 1, b: 2, c: { d: 4, e: [1, 2, 3] } });
+ });
+
+ bench('lodash/cloneDeep', () => {
+ cloneDeepLodash({ a: 1, b: 2, c: { d: 4, e: [1, 2, 3] } });
+ });
+});
diff --git a/packages/utils/src/common/deepCopy/deepCopy.spec.ts b/packages/utils/src/common/cloneDeep/cloneDeep.spec.ts
similarity index 76%
rename from packages/utils/src/common/deepCopy/deepCopy.spec.ts
rename to packages/utils/src/common/cloneDeep/cloneDeep.spec.ts
index ee5d045d4..796c72e61 100644
--- a/packages/utils/src/common/deepCopy/deepCopy.spec.ts
+++ b/packages/utils/src/common/cloneDeep/cloneDeep.spec.ts
@@ -1,17 +1,17 @@
import { describe, it, expect } from 'vitest';
-import { deepCopy } from '.';
+import { cloneDeep } from '.';
-describe('deepCopy', () => {
+describe('cloneDeep', () => {
it('should deeply copy a primitive value', () => {
const originNum = 42;
- const copiedNum = deepCopy(originNum);
+ const copiedNum = cloneDeep(originNum);
expect(copiedNum).toBe(originNum);
});
it('should deeply copy an array', () => {
const originArray = [1, 2, [3, 4]];
- const copiedArray = deepCopy(originArray);
+ const copiedArray = cloneDeep(originArray);
expect(copiedArray).toEqual(originArray);
expect(copiedArray).not.toBe(originArray);
@@ -21,7 +21,7 @@ describe('deepCopy', () => {
const originArray: any[] = [];
originArray.push(originArray);
- const copiedArr = deepCopy(originArray);
+ const copiedArr = cloneDeep(originArray);
expect(copiedArr).toEqual(copiedArr[0]);
expect(copiedArr).not.toBe(originArray);
@@ -32,7 +32,7 @@ describe('deepCopy', () => {
const originObject = { origin: {} };
originObject.origin = originObject;
- const copiedObject = deepCopy(originObject);
+ const copiedObject = cloneDeep(originObject);
expect(copiedObject).toEqual(copiedObject.origin);
expect(copiedObject).not.toBe(originObject);
@@ -40,16 +40,17 @@ describe('deepCopy', () => {
});
it('should deeply copy an object', () => {
- const originObj = { a: 1, b: { c: 2 } };
- const copiedObj = deepCopy(originObj);
+ const originObj = { a: 1, b: { c: 2, d: [0, 1] } };
+ const copiedObj = cloneDeep(originObj);
expect(copiedObj).toEqual(originObj);
expect(copiedObj).not.toBe(originObj);
+ expect(copiedObj.b.d).not.toBe(originObj.b.d);
});
it('should deeply copy a set', () => {
const originSet = new Set([1, 2, 3]);
- const copiedSet = deepCopy(originSet);
+ const copiedSet = cloneDeep(originSet);
expect(copiedSet).toEqual(originSet);
expect(copiedSet).not.toBe(originSet);
@@ -60,7 +61,7 @@ describe('deepCopy', () => {
['a', 1],
['b', 2],
]);
- const copiedMap = deepCopy(originMap);
+ const copiedMap = cloneDeep(originMap);
expect(copiedMap).toEqual(originMap);
expect(copiedMap).not.toBe(originMap);
@@ -68,7 +69,7 @@ describe('deepCopy', () => {
it('should deeply copy a date', () => {
const date = new Date();
- const copiedDate = deepCopy(date);
+ const copiedDate = cloneDeep(date);
expect(copiedDate.getTime()).toEqual(date.getTime());
expect(copiedDate).not.toBe(date);
@@ -76,7 +77,7 @@ describe('deepCopy', () => {
it('should deeply copy a regex', () => {
const regex = /test/gi;
- const copiedRegex = deepCopy(regex);
+ const copiedRegex = cloneDeep(regex);
expect(copiedRegex.source).toEqual(regex.source);
expect(copiedRegex.flags).toEqual(regex.flags);
diff --git a/packages/utils/src/common/deepCopy/index.ts b/packages/utils/src/common/cloneDeep/index.ts
similarity index 75%
rename from packages/utils/src/common/deepCopy/index.ts
rename to packages/utils/src/common/cloneDeep/index.ts
index 0632c0f9a..837d769b5 100644
--- a/packages/utils/src/common/deepCopy/index.ts
+++ b/packages/utils/src/common/cloneDeep/index.ts
@@ -1,4 +1,4 @@
-export function deepCopy(value: T) {
+export function cloneDeep(value: T) {
const referenceMap = new WeakMap();
const copyWthRecursion = (target: T): T => {
@@ -14,11 +14,11 @@ export function deepCopy(value: T) {
// Array
if (Array.isArray(target)) {
- const newArray: any[] = [];
-
+ const newArray = new Array(target.length);
referenceMap.set(target, newArray);
- for (const item of target) {
- newArray.push(copyWthRecursion(item));
+
+ for (let i = 0; i < target.length; i++) {
+ newArray[i] = copyWthRecursion(target[i]);
}
return newArray as T;
}
@@ -26,8 +26,8 @@ export function deepCopy(value: T) {
// Set
if (target instanceof Set) {
const newSet = new Set();
-
referenceMap.set(target, newSet);
+
for (const item of target) {
newSet.add(copyWthRecursion(item));
}
@@ -52,18 +52,21 @@ export function deepCopy(value: T) {
// RegExp
if (target instanceof RegExp) {
- return new RegExp(target.source, target.flags) as T;
+ const result = new RegExp(target.source, target.flags);
+ result.lastIndex = target.lastIndex;
+
+ return result as T;
}
// Object
- const newObject: Record = Object.create(
- Object.getPrototypeOf(target)
- );
-
+ const newObject: Record = {};
referenceMap.set(target, newObject);
+
const keys = Reflect.ownKeys(target); // symbol 유지
- for (const key of keys) {
+ for (let i = 0; i < keys.length; i++) {
+ const key = keys[i];
+
newObject[key] = copyWthRecursion(
(target as Record)[key]
);
diff --git a/packages/utils/src/common/index.ts b/packages/utils/src/common/index.ts
index 5209ce5a0..15594ef2a 100644
--- a/packages/utils/src/common/index.ts
+++ b/packages/utils/src/common/index.ts
@@ -1,6 +1,6 @@
export * from './abRandom';
export * from './asyncNoop';
-export * from './deepCopy';
+export * from './cloneDeep';
export * from './delay';
export * from './getUniqId';
export * from './getUniqTime';
diff --git a/packages/utils/src/common/wrapInArray/index.ts b/packages/utils/src/common/wrapInArray/index.ts
index c1778ef9f..faec0c547 100644
--- a/packages/utils/src/common/wrapInArray/index.ts
+++ b/packages/utils/src/common/wrapInArray/index.ts
@@ -1,7 +1,7 @@
-import { deepCopy } from '../deepCopy';
+import { cloneDeep } from '../cloneDeep';
export function wrapInArray(value: T | T[]): T[] {
- const copiedValue = deepCopy(value);
+ const copiedValue = cloneDeep(value);
return Array.isArray(copiedValue) ? copiedValue : [copiedValue];
}
diff --git a/packages/utils/src/object/omit/index.ts b/packages/utils/src/object/omit/index.ts
index a71af6099..b4420f828 100644
--- a/packages/utils/src/object/omit/index.ts
+++ b/packages/utils/src/object/omit/index.ts
@@ -1,3 +1,5 @@
+import { cloneDeep } from '../../common';
+
/**
* @description 주어진 객체에서 지정된 키들을 제거한 새로운 객체를 반환하는 함수입니다.
*
@@ -17,7 +19,7 @@ export function omit, K extends keyof T>(
obj: T,
keys: K[] | readonly K[]
): Omit {
- const result = { ...obj };
+ const result = cloneDeep(obj);
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
diff --git a/packages/utils/src/object/pick/index.ts b/packages/utils/src/object/pick/index.ts
index 670641eba..af814d08b 100644
--- a/packages/utils/src/object/pick/index.ts
+++ b/packages/utils/src/object/pick/index.ts
@@ -1,3 +1,5 @@
+import { cloneDeep } from '../../common';
+
/**
* @description 주어진 객체에서 지정된 키들만을 선택하여 새로운 객체를 반환하는 함수입니다.
*
@@ -23,7 +25,7 @@ export function pick, K extends keyof T>(
keys: K[] | readonly K[]
): Pick {
const result = {} as T;
- const copiedObj = { ...obj };
+ const copiedObj = cloneDeep(obj);
for (let i = 0; i < keys.length; i++) {
const key = keys[i];