Last active
October 31, 2023 18:18
-
-
Save dSalieri/6755d09257e28f1249e64f9c0ac0e1fe to your computer and use it in GitHub Desktop.
Revisions
-
dSalieri revised this gist
Jul 15, 2023 . 1 changed file with 11 additions and 10 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -17,7 +17,7 @@ function deepClone(obj, options) { }, }; const empty = Symbol("empty"); const map = new Map(); return (function clone(obj, who) { @@ -27,8 +27,9 @@ function deepClone(obj, options) { } else if (map.has(obj)) { return map.get(obj); } const ownKeys = Reflect.ownKeys(obj); let result = options.compatibleType === true && ownKeys.length > 0 ? new Object() : empty; switch (sortOf(obj)) { case "array": { @@ -48,16 +49,16 @@ function deepClone(obj, options) { map.set(obj, result); if (result === empty && options.compatibleType === false) { if (who === "parent") return null; return empty; } if (ownKeys.length === 0) { if (result !== empty) return result; if (who === "child") return empty; return null; } for (let key of ownKeys) { const { descriptor, type } = descriptorWithType(obj, key); @@ -68,7 +69,7 @@ function deepClone(obj, options) { ) continue; let cloned = clone(descriptor.value, "child"); if (cloned !== empty) { if (type === "data" && ["data", "both"].some((v) => v === options.descriptorType)) { Reflect.defineProperty(result, key, { ...descriptor, value: cloned }); } else if (type === "accessor" && ["accessor", "both"].some((v) => v === options.descriptorType)) { -
dSalieri revised this gist
Jul 15, 2023 . 1 changed file with 5 additions and 3 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -54,8 +54,10 @@ function deepClone(obj, options) { } const ownKeys = Reflect.ownKeys(obj); if (ownKeys.length === 0) { Reflect.setPrototypeOf(result, Reflect.getPrototypeOf(obj)); return result }; for (let key of ownKeys) { const { descriptor, type } = descriptorWithType(obj, key); @@ -95,4 +97,4 @@ function deepClone(obj, options) { return result; } } -
dSalieri revised this gist
Jul 15, 2023 . 1 changed file with 2 additions and 4 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -54,10 +54,8 @@ function deepClone(obj, options) { } const ownKeys = Reflect.ownKeys(obj); if (ownKeys.length === 0) return result; for (let key of ownKeys) { const { descriptor, type } = descriptorWithType(obj, key); -
dSalieri revised this gist
Jul 10, 2023 . 1 changed file with 3 additions and 3 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -49,13 +49,13 @@ function deepClone(obj, options) { map.set(obj, result); if (result === _null && options.compatibleType === false) { if (who === "parent") return null; return _null; } const ownKeys = Reflect.ownKeys(obj); if (ownKeys.length === 0) { if (who === "parent") return null; return _null; } @@ -67,7 +67,7 @@ function deepClone(obj, options) { (descriptor.configurable === false && options.descriptorProps.configurable === false) ) continue; let cloned = clone(descriptor.value, "child"); if (cloned !== _null) { if (type === "data" && ["data", "both"].some((v) => v === options.descriptorType)) { Reflect.defineProperty(result, key, { ...descriptor, value: cloned }); -
dSalieri revised this gist
Feb 26, 2023 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,7 +1,7 @@ **Цель:** Добиться копирования объекта в глубину. **Примечания:** 1. Копирование работает с: _`undefined`_, _`null`_, _`number`_, _`bigint`_, _`string`_, _`boolean`_, _`array`_, _`object`_. 2. Копирование не работает с: _`symbol`_, _`function`_. Они переносятся в клонируемый объект как есть (это из-за того как устроены внутри). 3. Копирование поддерживает другие сложные объекты, но реализация лежит на ваших плечах (внизу есть пример как это сделать). 4. Поддержка тех типов что не предоставлена, будут пропущены, ключи для них созданы не будут, но есть специальный флаг, который позволит сделать попытку скопировать свойство. -
dSalieri revised this gist
Feb 25, 2023 . 1 changed file with 3 additions and 2 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -19,6 +19,7 @@ function deepClone(obj, options) { const _null = Symbol("null"); const map = new Map(); return (function clone(obj, who) { if (!(typeof obj === "object" && obj !== null)) { if (who === "child" || typeof obj === "function") return obj; @@ -54,8 +55,8 @@ function deepClone(obj, options) { const ownKeys = Reflect.ownKeys(obj); if (ownKeys.length === 0) { if(who === "parent") return null; return _null; } for (let key of ownKeys) { -
dSalieri revised this gist
Feb 25, 2023 . 1 changed file with 6 additions and 7 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -26,12 +26,8 @@ function deepClone(obj, options) { } else if (map.has(obj)) { return map.get(obj); } let result = options.compatibleType === true ? new Object() : _null; switch (sortOf(obj)) { case "array": { @@ -51,7 +47,10 @@ function deepClone(obj, options) { map.set(obj, result); if (result === _null && options.compatibleType === false) { if (who === "parent") return null return _null; } const ownKeys = Reflect.ownKeys(obj); if (ownKeys.length === 0) { -
dSalieri revised this gist
Feb 25, 2023 . 1 changed file with 4 additions and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -68,6 +68,10 @@ let o1 = { date: new Date(), map: new Map([[{id:1},"water"],[{id:2},"fire"],[{id:3},"air"]]) }; /// Накидываем циклические ссылки o1.data.toListCycle = o1.list; o1.list.toDataCycle = o1.data; o1.toItself = o1; /// Клонируем let cloned = deepClone(o1, {supplementalTypes: cloneObject}); /// Смотрим на результат, можно конечно вручную в консоли потрогать для убедительности -
dSalieri revised this gist
Feb 25, 2023 . 1 changed file with 5 additions and 2 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -44,7 +44,7 @@ function deepClone(obj, options) { } default: { if (Object.hasOwnProperty.call(options.supplementalTypes, sortOf(obj))) { return options.supplementalTypes[sortOf(obj)](obj, clone); } } } @@ -54,7 +54,10 @@ function deepClone(obj, options) { if (result === _null && options.compatibleType === false && who === "child") return _null; const ownKeys = Reflect.ownKeys(obj); if (ownKeys.length === 0) { if(who === "parent") return null; return _null; } for (let key of ownKeys) { const { descriptor, type } = descriptorWithType(obj, key); -
dSalieri revised this gist
Feb 24, 2023 . 1 changed file with 5 additions and 4 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -17,6 +17,7 @@ function deepClone(obj, options) { }, }; const _null = Symbol("null"); const map = new Map(); return (function clone(obj, who) { if (!(typeof obj === "object" && obj !== null)) { @@ -30,7 +31,7 @@ function deepClone(obj, options) { ? new Object() : who === "child" && options.compatibleType === true ? new Object() : _null; switch (sortOf(obj)) { case "array": { @@ -50,10 +51,10 @@ function deepClone(obj, options) { map.set(obj, result); if (result === _null && options.compatibleType === false && who === "child") return _null; const ownKeys = Reflect.ownKeys(obj); if (ownKeys.length === 0 && options.compatibleType === false) return _null; for (let key of ownKeys) { const { descriptor, type } = descriptorWithType(obj, key); @@ -64,7 +65,7 @@ function deepClone(obj, options) { ) continue; let cloned = clone(Reflect.get(obj, key), "child"); if (cloned !== _null) { if (type === "data" && ["data", "both"].some((v) => v === options.descriptorType)) { Reflect.defineProperty(result, key, { ...descriptor, value: cloned }); } else if (type === "accessor" && ["accessor", "both"].some((v) => v === options.descriptorType)) { -
dSalieri revised this gist
Feb 24, 2023 . 1 changed file with 1 addition and 2 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -57,14 +57,13 @@ function deepClone(obj, options) { for (let key of ownKeys) { const { descriptor, type } = descriptorWithType(obj, key); if ( (descriptor.enumerable === false && options.descriptorProps.enumerable === false) || (descriptor.writable === false && options.descriptorProps.writable === false) || (descriptor.configurable === false && options.descriptorProps.configurable === false) ) continue; let cloned = clone(Reflect.get(obj, key), "child"); if (cloned !== null) { if (type === "data" && ["data", "both"].some((v) => v === options.descriptorType)) { Reflect.defineProperty(result, key, { ...descriptor, value: cloned }); -
dSalieri revised this gist
Feb 24, 2023 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -10,7 +10,7 @@ **Опции:** ```JavaScript { prototype: true/false/null, /// копирует ссылку на прототип в копируемый объект, null - установка прототипа в значение null compatibleType: true/false, /// данная опция делает попытку скопировать объект, тип которого не поддерживается, если попытка неудачна свойство не будет создано descriptorType: "both"/"data"/"accessor", /// от указанного типа зависит копирование свойств конкретного типа descriptorProps: { -
dSalieri revised this gist
Feb 24, 2023 . 1 changed file with 2 additions and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -22,6 +22,8 @@ function deepClone(obj, options) { if (!(typeof obj === "object" && obj !== null)) { if (who === "child" || typeof obj === "function") return obj; else throw Error("Can't clone primitive value"); } else if (map.has(obj)) { return map.get(obj); } let result = who === "parent" -
dSalieri revised this gist
Feb 24, 2023 . 1 changed file with 3 additions and 2 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -19,14 +19,15 @@ writable: true/false, enumerable: true/false, configurable: true/false, }, supplementalTypes: {} /// в объекте указываются специальные методы, которые реализуют специальные объекты } ``` Советую поэкспериментировать чтобы четко понять как работают данные флаги. **Как добавить поддержку специального типа (на примере _`Set`_, _`Map`_ и _`Date`_):** Нужно передать во второй аргумент объект со свойством `supplementalTypes` где свойства это имена типов данных, например для типа _`Set`_, свойство `set`, для _`Map`_ свойство `map`, для _`Date`_ свойство `date` итд. Функция, которая устанавливается такому свойству может быть определена как угодно. Параметры у функции: первый это объект, который клонируется, второй это клонируемая функция из алгоритма. ```JavaScript const cloneObject = { set: function (object, cloneF) { -
dSalieri created this gist
Feb 24, 2023 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,74 @@ **Цель:** Добиться копирования объекта в глубину. **Примечания:** 1. Копирование работает с: _`undefined`_, _`null`_, _`number`_, _`string`_, _`boolean`_, _`array`_, _`object`_. 2. Копирование не работает с: _`symbol`_, _`function`_. Они переносятся в клонируемый объект как есть (это из-за того как устроены внутри). 3. Копирование поддерживает другие сложные объекты, но реализация лежит на ваших плечах (внизу есть пример как это сделать). 4. Поддержка тех типов что не предоставлена, будут пропущены, ключи для них созданы не будут, но есть специальный флаг, который позволит сделать попытку скопировать свойство. 5. Копирование работает со всеми типами свойств, дескриптор каждого свойства учитывается. **Опции:** ```JavaScript { prototype: true/false, /// копирует ссылку на прототип в копируемый объект compatibleType: true/false, /// данная опция делает попытку скопировать объект, тип которого не поддерживается, если попытка неудачна свойство не будет создано descriptorType: "both"/"data"/"accessor", /// от указанного типа зависит копирование свойств конкретного типа descriptorProps: { /// если указывается false то это означает что свойство с данным дескриптором и со значением false не учитывается, а значит не копируется; /// если указывается true, тогда не играет роли какое значение имеет свойство true или false - оно будет скопировано writable: true/false, enumerable: true/false, configurable: true/false, } } ``` Советую поэкспериментировать чтобы четко понять как работают данные флаги. **Как добавить поддержку специального типа (на примере _`Set`_, _`Map`_ и _`Date`_):** Нужно передать во второй аргумент объект со свойством supplementalTypes где свойства это имена типов данных, например для типа _`Set`_, свойство `set`, для _`Map`_ свойство `map`, для _`Date`_ свойство `date` итд. Функция, которая устанавливается такому свойству может быть определена как угодно. Параметры у функции: первый это объект, который клонируется, второй это клонируемая функция из алгоритма. ```JavaScript const cloneObject = { set: function (object, cloneF) { let result = new Set(); for (let data of object) { if (typeof data === "object" && data !== null) result.add(cloneF(data)); else result.add(data); } return result; }, map: function (object, cloneF) { let result = new Map(); for (let [key, value] of object) { if (typeof value === "object" && value !== null) result.set(key, cloneF(value)); else result.set(key, value); } return result; }, date: function (object, cloneF) { return new Date(object.getTime()); }, }; ``` **Тест (не забываем взять из исходника выше реализованные типы данных)**: ```JavaScript let o1 = { name: "Maxim", data: { key1: "62s34i8g72s", key2: "82s3438g72s", key3: "72s34m8g72s", }, list: [1, 2, 3, 4, 5, new Set(["look", "at", "that"])], specialList: new Set(["one", "two", "three"]), date: new Date(), map: new Map([[{id:1},"water"],[{id:2},"fire"],[{id:3},"air"]]) }; /// Клонируем let cloned = deepClone(o1, {supplementalTypes: cloneObject}); /// Смотрим на результат, можно конечно вручную в консоли потрогать для убедительности console.log(o1.list[5] === cloned.list[5]); /// expected: false ``` This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,95 @@ function deepClone(obj, options) { options = { prototype: true, compatibleType: true, descriptorType: "both", ...{ ...options, descriptorProps: { writable: true, enumerable: true, configurable: true, ...options?.descriptorProps, }, supplementalTypes: { ...options?.supplementalTypes }, }, }; const map = new Map(); return (function clone(obj, who) { if (!(typeof obj === "object" && obj !== null)) { if (who === "child" || typeof obj === "function") return obj; else throw Error("Can't clone primitive value"); } let result = who === "parent" ? new Object() : who === "child" && options.compatibleType === true ? new Object() : null; switch (sortOf(obj)) { case "array": { result = new Array(); break; } case "object": { result = new Object(); break; } default: { if (Object.hasOwnProperty.call(options.supplementalTypes, sortOf(obj))) { result = options.supplementalTypes[sortOf(obj)](obj, clone); } } } map.set(obj, result); if (result === null && options.compatibleType === false && who === "child") return null; const ownKeys = Reflect.ownKeys(obj); if (ownKeys.length === 0 && options.compatibleType === false) return null; for (let key of ownKeys) { const { descriptor, type } = descriptorWithType(obj, key); if ( (descriptor.enumerable === false && options.descriptorProps.enumerable === false) || (descriptor.writable === false && options.descriptorProps.writable === false) || (descriptor.configurable === false && options.descriptorProps.configurable === false) ) continue; let cloned = clone(obj[key], "child"); if (cloned !== null) { if (type === "data" && ["data", "both"].some((v) => v === options.descriptorType)) { Reflect.defineProperty(result, key, { ...descriptor, value: cloned }); } else if (type === "accessor" && ["accessor", "both"].some((v) => v === options.descriptorType)) { Reflect.defineProperty(result, key, { ...descriptor }); } } } if (options.prototype === true || options.prototype === null) { Reflect.setPrototypeOf(result, options.prototype === null ? null : Reflect.getPrototypeOf(obj)); } return result; })(obj, "parent"); function sortOf(arg) { return Object.prototype.toString.call(arg).slice(8, -1).toLowerCase(); } function descriptorWithType(obj, prop) { const desc = Reflect.getOwnPropertyDescriptor(obj, prop); const result = { descriptor: desc, type: undefined }; if (["writable", "value"].some((v) => Reflect.has(desc, v))) result.type = "data"; else if (["get", "set"].some((v) => Reflect.has(desc, v))) result.type = "accessor"; return result; } }