@codady/utils 0.0.17 → 0.0.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/utils.umd.js CHANGED
@@ -1,8 +1,8 @@
1
1
 
2
2
  /*!
3
- * @since Last modified: 2025-12-26 16:3:51
3
+ * @since Last modified: 2026-1-5 10:34:3
4
4
  * @name Utils for web front-end.
5
- * @version 0.0.17
5
+ * @version 0.0.19
6
6
  * @author AXUI development team <3217728223@qq.com>
7
7
  * @description This is a set of general-purpose JavaScript utility functions developed by the AXUI team. All functions are pure and do not involve CSS or other third-party libraries. They are suitable for any web front-end environment.
8
8
  * @see {@link https://www.axui.cn|Official website}
@@ -518,6 +518,8 @@
518
518
  // Whether to allow merging key=symbol key-value pairs when target is {} type.
519
519
  // target是{}类型时,是否允许合并key=symbol的键值对。
520
520
  useSymbol: true,
521
+ nullBehavior: 'preserve',
522
+ undefinedBehavior: 'preserve',
521
523
  // Options passed to the deepClone function when targetClone is true
522
524
  // 当targetClone为true时传递给deepClone函数的选项
523
525
  deepClone: {},
@@ -606,18 +608,38 @@
606
608
  // 如果是复制方法,则先复制target
607
609
  result = options.targetClone ? shallowCopy(target) : target;
608
610
  for (let k in source) {
611
+ const _result = result[k], _source = source[k];
609
612
  if (source.hasOwnProperty(k) && result.hasOwnProperty(k)) {
610
- let resp = smartMerger(result[k], source[k], { ...opts, parent: result });
613
+ const resp = smartMerger(_result, _source, { ...opts, parent: result });
611
614
  //resp={result,flag,type}
612
- //flag=true表示类型一致并完成了合并,false表示并没有合并需要直接赋值
615
+ //flag=true表示类型一致(object/array/map/set)并完成了合并,false表示并没有合并需要直接赋值
613
616
  if (!resp.flag) {
614
617
  //类型不同则直接覆盖
615
- if (options.useEnable) {
616
- result[k] = mergeEnableObject(result[k], source[k]);
618
+ let tmp = options.useEnable ? mergeEnableObject(_result, _source) : _source;
619
+ if (_result !== tmp && tmp === null) {
620
+ if (options.nullBehavior === 'ignore') ;
621
+ else if (options.nullBehavior === 'delete') {
622
+ //删除属性
623
+ Reflect.deleteProperty(result, k);
624
+ }
625
+ else {
626
+ //替换
627
+ result[k] = tmp;
628
+ }
629
+ }
630
+ else if (_result !== tmp && tmp === undefined) {
631
+ if (options.undefinedBehavior === 'ignore') ;
632
+ else if (options.undefinedBehavior === 'delete') {
633
+ //删除属性
634
+ Reflect.deleteProperty(result, k);
635
+ }
636
+ else {
637
+ //替换
638
+ result[k] = _source;
639
+ }
617
640
  }
618
641
  else {
619
- //完全替换
620
- result[k] = source[k];
642
+ result[k] = _source;
621
643
  }
622
644
  }
623
645
  else {
@@ -630,13 +652,13 @@
630
652
  }
631
653
  else {
632
654
  //其他类型则直接覆盖
633
- result[k] = source[k];
655
+ result[k] = _source;
634
656
  }
635
657
  }
636
658
  }
637
659
  else if (source.hasOwnProperty(k) && !result.hasOwnProperty(k) && options.inheritMissing) {
638
660
  //如果source有属性,result没有该属性,但是options允许追加属性则直接赋值
639
- result[k] = source[k];
661
+ result[k] = _source;
640
662
  }
641
663
  }
642
664
  //Symbol键直接追加,因为Symbol是唯一,结果同Object.assign
@@ -743,6 +765,146 @@
743
765
  return smartMerger(target, source, options).result;
744
766
  };
745
767
 
768
+ const getEl = (obj, wrap = document.body) => {
769
+ let objType = getDataType(obj), parType = getDataType(wrap), parent = parType.includes('HTML') ? wrap : document.querySelector(wrap),
770
+ //如果parent是template节点,需要通过node.content.querySelector取得子节点
771
+ root = parent && parent instanceof HTMLTemplateElement ? parent.content : parent, result = null;
772
+ if (obj) {
773
+ if (objType.includes('HTML')) {
774
+ result = obj;
775
+ }
776
+ else if (objType === 'String') {
777
+ try {
778
+ result = (root || document).querySelector(obj.trim());
779
+ //可能会报错,报错则返回null
780
+ }
781
+ catch {
782
+ result = null;
783
+ }
784
+ }
785
+ }
786
+ return result;
787
+ };
788
+
789
+ const isEmpty = (data) => {
790
+ let type = getDataType(data), flag;
791
+ if (!data) {
792
+ //0,'',false,undefined,null
793
+ flag = true;
794
+ }
795
+ else {
796
+ //function(){}|()=>{}
797
+ //[null]|[undefined]|['']|[""]
798
+ //[]|{}
799
+ //Symbol()|Symbol.for()
800
+ //Set,Map
801
+ //Date/Regex
802
+ flag = (type === 'Object') ? (Object.keys(data).length === 0) :
803
+ (type === 'Array') ? data.join('') === '' :
804
+ (type === 'Function') ? (data.toString().replace(/\s+/g, '').match(/{.*}/g)[0] === '{}') :
805
+ (type === 'Symbol') ? (data.toString().replace(/\s+/g, '').match(/\(.*\)/g)[0] === '()') :
806
+ (type === 'Set' || type === 'Map') ? data.size === 0 :
807
+ type === 'Date' ? isNaN(data.getTime()) :
808
+ type === 'RegExp' ? data.source === '' :
809
+ type === 'ArrayBuffer' ? data.byteLength === 0 :
810
+ (type === 'NodeList' || type === 'HTMLCollection') ? data.length === 0 :
811
+ ('length' in data && typeof data.length === 'number') ? data.length === 0 :
812
+ ('size' in data && typeof data.size === 'number') ? data.size === 0 :
813
+ (type === 'Error' || data instanceof Error) ? data.message === '' :
814
+ (type.includes('Array') && (['Uint8Array', 'Int8Array', 'Uint16Array', 'Int16Array', 'Uint32Array', 'Int32Array', 'Float32Array', 'Float64Array'].includes(type))) ? data.length === 0 :
815
+ false;
816
+ }
817
+ return flag;
818
+ };
819
+
820
+ const getEls = (data, parent = document.body) => {
821
+ let type = getDataType(data), parentEl = getEl(parent), root = parentEl && parentEl instanceof HTMLTemplateElement ? parentEl.content : (parentEl || document), result = [];
822
+ //data为空直接返回空数组
823
+ if (isEmpty(data)) {
824
+ return result;
825
+ }
826
+ if (type.includes('HTML')) {
827
+ //一个节点
828
+ result.push(data);
829
+ }
830
+ else if (type === 'String') {
831
+ data = data.trim();
832
+ //以英文逗号作为节点选择器分隔符
833
+ result = data.split(',').map((k) => {
834
+ return [...root.querySelectorAll(k)];
835
+ }).flat();
836
+ }
837
+ else if (type === 'Array') {
838
+ result = data.map((k) => {
839
+ return getEl(k, parentEl);
840
+ });
841
+ }
842
+ return result.filter(Boolean);
843
+ };
844
+
845
+ const createEl = (name, attrs, content) => {
846
+ //默认为div
847
+ name = name || 'div';
848
+ //统一大小写
849
+ let rootName = name.toUpperCase().trim(), rootEl = document.createElement(rootName), attrsType = getDataType(attrs), loop = (host, data) => {
850
+ if (data === '' || data === null || data === undefined) {
851
+ //为空、未定义则不再执行
852
+ return false;
853
+ }
854
+ let dataType = getDataType(data);
855
+ //template是DocumentFragment类型不能用insertAdjacentHTML
856
+ if (rootName === 'TEMPLATE') {
857
+ host.innerHTML = data.toString();
858
+ }
859
+ else {
860
+ if (dataType === 'Array' && data.length > 0) {
861
+ //节点数组
862
+ //data.forEach((i: T_obj) => loop(el, i));
863
+ for (let k of data) {
864
+ let childType = getDataType(k);
865
+ if (childType.includes('HTML')) {
866
+ //是个节点
867
+ host.appendChild(k);
868
+ }
869
+ else {
870
+ //是个对象{name:'',attrs:{},content:''}
871
+ let child = createEl(k.name, k.attrs, k.content);
872
+ child && host.appendChild(child);
873
+ }
874
+ }
875
+ }
876
+ else if (dataType.includes('HTML')) {
877
+ //HTML节点
878
+ host.appendChild(data);
879
+ }
880
+ else if (dataType === 'String' && data.trim().startsWith('#') && data.trim().length > 1) {
881
+ //是字符串且是#id选择器,则取其文本
882
+ let el = getEl(data);
883
+ if (!el)
884
+ return;
885
+ //如果是template模板节点则需要特殊处理
886
+ el.nodeName === 'TEMPLATE' ? host.appendChild(el.content.cloneNode(true)) : host.insertAdjacentHTML('beforeEnd', el.innerHTML);
887
+ }
888
+ else {
889
+ //字符串数字等
890
+ host.insertAdjacentHTML('beforeEnd', data);
891
+ }
892
+ }
893
+ };
894
+ //添加属性
895
+ if (attrs && attrsType === 'Object') {
896
+ for (let k in attrs) {
897
+ //注意,attrs[k]可能是一个{}或[],不一定是字符串
898
+ // JSON.stringify可以将所有格式的数据都转成文本,会忽略函数和节点数据
899
+ //字符串则不需要stringify,否则会将字符串的引号也一并输出
900
+ attrs.hasOwnProperty(k) && rootEl.setAttribute(k, typeof attrs[k] === 'string' ? attrs[k] : JSON.stringify(attrs[k]));
901
+ }
902
+ }
903
+ //执行循环创建子节点
904
+ loop(rootEl, content);
905
+ return rootEl;
906
+ };
907
+
746
908
  const utils = {
747
909
  //executeStr,
748
910
  getDataType,
@@ -761,6 +923,9 @@
761
923
  deepMerge,
762
924
  shallowCopy,
763
925
  copyObjectWithSymbol,
926
+ getEl,
927
+ getEls,
928
+ createEl,
764
929
  };
765
930
 
766
931
  return utils;
@@ -1,7 +1,7 @@
1
1
  /*!
2
- * @since Last modified: 2025-12-26 16:3:51
2
+ * @since Last modified: 2026-1-5 10:34:3
3
3
  * @name Utils for web front-end.
4
- * @version 0.0.17
4
+ * @version 0.0.19
5
5
  * @author AXUI development team <3217728223@qq.com>
6
6
  * @description This is a set of general-purpose JavaScript utility functions developed by the AXUI team. All functions are pure and do not involve CSS or other third-party libraries. They are suitable for any web front-end environment.
7
7
  * @see {@link https://www.axui.cn|Official website}
@@ -12,4 +12,4 @@
12
12
  * @copyright This software supports the MIT License, allowing free learning and commercial use, but please retain the terms 'ax,' 'axui,' 'AX,' and 'AXUI' within the software.
13
13
  * @license MIT license
14
14
  */
15
- !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).utils=t()}(this,function(){"use strict";const getDataType=e=>{let t,r=Object.prototype.toString.call(e).slice(8,-1);return t="Function"===r&&/^\s*class\s+/.test(e.toString())?"Class":"Object"===r&&Object.getPrototypeOf(e)!==Object.prototype?"Instance":r,t},deepClone=(e,t={})=>{const r=getDataType(e),n=Object.assign({cloneSet:!0,cloneMap:!0,cloneObject:!0,cloneArray:!0,cloneDate:!0,cloneRegex:!0},t);if(n.interceptor&&"function"==typeof n.interceptor){let t=n.interceptor({input:e,type:r,parent:n.parent});if(t)return t}n.onBeforeClone?.({input:e,type:r,parent:n.parent});let o,a=!0;if("Object"===r&&n.cloneObject){const t={},r=Object.getOwnPropertySymbols(e);for(const r in e)t[r]=deepClone(e[r],n);if(r.length>0)for(const o of r)t[o]=deepClone(e[o],{...n,parent:e});o=t}else if("Array"===r&&n.cloneArray)o=e.map(t=>deepClone(t,{...n,parent:e}));else if("Map"===r&&n.cloneMap){const t=new Map;for(const[r,o]of e)t.set(deepClone(r,n),deepClone(o,{...n,parent:e}));o=t}else if("Set"===r&&n.cloneSet){const t=new Set;for(const r of e)t.add(deepClone(r,{...n,parent:e}));o=t}else if("Date"===r&&n.cloneDate)o=new Date(e.getTime());else if("RegExp"===r&&n.cloneRegex){const t=e;o=new RegExp(t.source,t.flags)}else o=e,a=!1;return n.onAfterClone?.({output:o,input:e,type:r,cloned:a,parent:n.parent}),o},deepCloneToJSON=e=>{const t=getDataType(e);if("Object"===t){const t={};for(const r in e)t[r]=deepCloneToJSON(e[r]);for(const e in t)void 0===t[e]&&Reflect.deleteProperty(t,e);return t}if("Array"===t){return e.map((e,t)=>deepCloneToJSON(e)).filter(e=>void 0!==e)}return["Number","String","Boolean","Null"].includes(t)?e:void 0},e=["push","pop","shift","unshift","splice","sort","reverse","copyWithin","fill"],t=["add","delete","clear"],r=["set","delete","clear"],copyObjectWithSymbol=e=>{if(!e||"object"!=typeof e)return e;const t=e,r=Object.getOwnPropertySymbols(t).reduce((e,r)=>(e[r]=t[r],e),{});return{...t,...r}},shallowCopy=(e,t={})=>{const r=getDataType(e);return"Set"===r?new Set([...e]):"Map"===r?new Map([...e]):Array.isArray(e)?[...e]:"object"===r?copyObjectWithSymbol(e):"Date"===r?new Date(e.getTime()):"RegExp"===r?new RegExp(e.source,e.flags):"Buffer"===r?Buffer.from(e):"ArrayBuffer"===r||ArrayBuffer.isView(e)?e.slice(0):"WeakSet"===r?new WeakSet([...e]):"WeakMap"===r?new WeakMap([...e]):"Error"===r?new Error(e.message):e};return{getDataType:getDataType,requireTypes:(e,t,r)=>{let n=Array.isArray(t)?t:[t],o=getDataType(e),a=o.toLowerCase(),s=n.map(e=>e.toLowerCase()),i=a.includes("html")?"element":a;if(r)try{if(!s.includes(i))throw new TypeError(`Expected data type(s): [${s.join(", ")}], but got: ${i}`)}catch(e){r(e,o)}else if(!s.includes(i))throw new TypeError(`Expected data type(s): [${s.join(", ")}], but got: ${i}`);return o},deepClone:deepClone,deepCloneToJSON:deepCloneToJSON,wrapArrayMethods:({target:t,onBeforeMutate:r=()=>{},onAfterMutate:n=()=>{},allowList:o,props:a={}})=>{if(!Array.isArray(t))throw new TypeError("The 'target' parameter must be an array.");o&&!o?.length||(o=e);const s={};for(let e of o)s[e]=function(...o){const s={},i=t.length;switch(e){case"push":case"unshift":s.addedItems=[...o];break;case"pop":s.poppedItem=t[i-1];break;case"shift":s.shiftedItem=t[0];break;case"splice":const[e,r]=o,n=e<0?Math.max(i+e,0):Math.min(e,i),a=void 0===r?i-n:r;s.deletedItems=t.slice(n,n+a);break;case"sort":case"reverse":s.oldSnapshot=[...t];break;case"fill":case"copyWithin":const c=o[1]||0,l=void 0===o[2]?i:o[2];s.oldItems=t.slice(c,l),s.start=c,s.end=l}r?.(s);const c=Array.prototype[e].apply(t,o),l={value:c,key:e,args:o,context:s,target:t,...a};return n?.(l),c};return s},arrayMutableMethods:e,setMutableMethods:t,mapMutableMethods:r,wrapSetMethods:({target:e,onBeforeMutate:r=()=>{},onAfterMutate:n=()=>{},allowList:o=t,props:a={}})=>{if(!(e instanceof Set))throw new TypeError("The 'target' parameter must be a Set.");const s={},createWrappedMethod=t=>function(...o){const s={};switch(t){case"add":{const[t]=o;s.addedItem=t,s.existed=e.has(t);break}case"delete":{const[t]=o;s.existed=e.has(t),s.deletedItem=s.existed?t:void 0;break}case"clear":s.clearedItems=Array.from(e),s.previousSize=e.size}r(s);const i=e[t].apply(e,o),c={method:t,result:i,args:o,context:s,target:e,...a};return n(c),i};for(const e of o)t.includes(e)&&(s[e]=createWrappedMethod(e));return Object.defineProperty(s,"target",{get:()=>e,enumerable:!1,configurable:!1}),s},wrapMapMethods:({target:e,onBeforeMutate:t=()=>{},onAfterMutate:n=()=>{},allowList:o=r,props:a={}})=>{if(!(e instanceof Map))throw new TypeError("The 'target' parameter must be a Map.");const s={},createWrappedMethod=r=>function(...o){const s={};switch(r){case"set":{const[t,r]=o;s.key=t,s.newValue=r,s.existed=e.has(t),s.oldValue=s.existed?e.get(t):void 0;break}case"delete":{const[t]=o;s.key=t,s.existed=e.has(t),s.value=s.existed?e.get(t):void 0;break}case"clear":s.clearedItems=Array.from(e.entries()),s.previousSize=e.size}t(s);const i=e[r].apply(e,o),c={method:r,result:i,args:o,context:s,target:e,...a};return n(c),i};for(const e of o)r.includes(e)&&(s[e]=createWrappedMethod(e));return Object.defineProperty(s,"target",{get:()=>e,enumerable:!1,configurable:!1}),s},getUniqueId:(e={})=>{const t=e.prefix,r=e.suffix,n=e.base10,o=e.base36;return`${t?t+"-":""}${Date.now()}${o?"-"+Math.random().toString(36).substring(2,11):""}${n?"-"+Math.floor(1e4*Math.random()).toString().padStart(4,"0"):""}${r?"-"+r:""}`},deepMerge:(e,t,r={})=>{const n=Object.assign({dataMode:"clear",inheritMissing:!0,targetClone:!1,useEnable:!0,useSymbol:!0,deepClone:{},onBeforeMerge:void 0,onAfterMerge:void 0},r),smartMerger=(e,t,n)=>{let o,a,s=getDataType(e),i=getDataType(t),c=!0;if(n.interceptor&&"function"==typeof n.interceptor){let r=n.interceptor({target:e,source:t,targetType:s,sourceType:i,parent:n.parent});if(r){if(null===r?.target||null===r?.source)return r;e=r.target,t=r.source}}return n?.onBeforeMerge?.({target:e,source:t,targetType:s,sourceType:i,parent:n.parent}),"Object"===s&&"Object"===i?(a=deepMergeObjects(e,t,n),o="Object"):"Array"===s&&"Array"===i?(a=deepMergeArrays(e,t,n),o="Array"):"Set"===s&&"Set"===i?(a=deepMergeSets(e,t,n),o="Set"):"Map"===s&&"Map"===i?(a=deepMergeMaps(e,t,n),o="Map"):(c=!1,a=e),n?.onAfterMerge?.({result:a,target:e,source:t,targetType:s,sourceType:i,mergeType:o,parent:r.parent}),{result:a,flag:c,mergeType:o}},mergeEnableObject=(e,t)=>e?.hasOwnProperty("enable")&&"boolean"==typeof t?(e.enable=t,e):t?.hasOwnProperty("enable")&&"boolean"==typeof e?Object.assign({enable:e},t):t,deepMergeObjects=(e,t,r={})=>{let n=getDataType(e),o=getDataType(t);if("Object"!==n||"Object"!==o)return e;const a=Object.assign({inheritMissing:!0,targetClone:!1,useEnable:!0},r);let s={};s=a.targetClone?shallowCopy(e):e;for(let e in t)if(t.hasOwnProperty(e)&&s.hasOwnProperty(e)){let n=smartMerger(s[e],t[e],{...r,parent:s});n.flag?n.mergeType?"Object"===n.mergeType&&(s[e]=n.result):s[e]=t[e]:a.useEnable?s[e]=mergeEnableObject(s[e],t[e]):s[e]=t[e]}else t.hasOwnProperty(e)&&!s.hasOwnProperty(e)&&a.inheritMissing&&(s[e]=t[e]);if(a.useSymbol){let e=Object.getOwnPropertySymbols(t);if(e.length)for(let r of e)s[r]=t[r]}return s},deepMergeArrays=(e,t,r={})=>{if(!Array.isArray(e)||!Array.isArray(t))return e;const n=Object.assign({dataMode:"clear",inheritMissing:!0,targetClone:!1},r),o=n.targetClone?[...e]:e;if("replace"===n.dataMode)for(let e=0;e<t.length&&(n.inheritMissing||!(e>=o.length));e++){smartMerger(o[e],t[e],{...n,parent:o}).flag||(o[e]=t[e])}else"concat"===n.dataMode||(o.length=0),o.push(...t);return o},deepMergeMaps=(e,t,r={})=>{if(!(e instanceof Map&&t instanceof Map))return e;const n=Object.assign({inheritMissing:!0,targetClone:!1,useEnable:!0},r),o=n.targetClone?new Map([...e]):e;for(const[e,a]of t.entries())if(o.has(e)){const t=o.get(e),r=a,s=smartMerger(t,r,n);s.flag?"Object"===s.mergeType&&o.set(e,s.result):o.set(e,r)}else r.inheritMissing&&o.set(e,a);return o},deepMergeSets=(e,t,r={})=>{if(!(e instanceof Set&&t instanceof Set))return e;const n=Object.assign({dataMode:"clear",inheritMissing:!0,targetClone:!1,useEnable:!0},r),o=n.targetClone?new Set(...e):e;if("replace"===n.dataMode){const e=[...o],r=[...t],a=smartMerger(e,r,n);o.clear();for(let e of a.result)o.add(e)}else if("concat"===n.dataMode)for(let e of t)o.add(e);else{o.clear();for(let e of t)o.add(e)}return o};return smartMerger(e,t,n).result},shallowCopy:shallowCopy,copyObjectWithSymbol:copyObjectWithSymbol}});
15
+ !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).utils=t()}(this,function(){"use strict";const getDataType=e=>{let t,r=Object.prototype.toString.call(e).slice(8,-1);return t="Function"===r&&/^\s*class\s+/.test(e.toString())?"Class":"Object"===r&&Object.getPrototypeOf(e)!==Object.prototype?"Instance":r,t},deepClone=(e,t={})=>{const r=getDataType(e),n=Object.assign({cloneSet:!0,cloneMap:!0,cloneObject:!0,cloneArray:!0,cloneDate:!0,cloneRegex:!0},t);if(n.interceptor&&"function"==typeof n.interceptor){let t=n.interceptor({input:e,type:r,parent:n.parent});if(t)return t}n.onBeforeClone?.({input:e,type:r,parent:n.parent});let o,a=!0;if("Object"===r&&n.cloneObject){const t={},r=Object.getOwnPropertySymbols(e);for(const r in e)t[r]=deepClone(e[r],n);if(r.length>0)for(const o of r)t[o]=deepClone(e[o],{...n,parent:e});o=t}else if("Array"===r&&n.cloneArray)o=e.map(t=>deepClone(t,{...n,parent:e}));else if("Map"===r&&n.cloneMap){const t=new Map;for(const[r,o]of e)t.set(deepClone(r,n),deepClone(o,{...n,parent:e}));o=t}else if("Set"===r&&n.cloneSet){const t=new Set;for(const r of e)t.add(deepClone(r,{...n,parent:e}));o=t}else if("Date"===r&&n.cloneDate)o=new Date(e.getTime());else if("RegExp"===r&&n.cloneRegex){const t=e;o=new RegExp(t.source,t.flags)}else o=e,a=!1;return n.onAfterClone?.({output:o,input:e,type:r,cloned:a,parent:n.parent}),o},deepCloneToJSON=e=>{const t=getDataType(e);if("Object"===t){const t={};for(const r in e)t[r]=deepCloneToJSON(e[r]);for(const e in t)void 0===t[e]&&Reflect.deleteProperty(t,e);return t}if("Array"===t){return e.map((e,t)=>deepCloneToJSON(e)).filter(e=>void 0!==e)}return["Number","String","Boolean","Null"].includes(t)?e:void 0},e=["push","pop","shift","unshift","splice","sort","reverse","copyWithin","fill"],t=["add","delete","clear"],r=["set","delete","clear"],copyObjectWithSymbol=e=>{if(!e||"object"!=typeof e)return e;const t=e,r=Object.getOwnPropertySymbols(t).reduce((e,r)=>(e[r]=t[r],e),{});return{...t,...r}},shallowCopy=(e,t={})=>{const r=getDataType(e);return"Set"===r?new Set([...e]):"Map"===r?new Map([...e]):Array.isArray(e)?[...e]:"object"===r?copyObjectWithSymbol(e):"Date"===r?new Date(e.getTime()):"RegExp"===r?new RegExp(e.source,e.flags):"Buffer"===r?Buffer.from(e):"ArrayBuffer"===r||ArrayBuffer.isView(e)?e.slice(0):"WeakSet"===r?new WeakSet([...e]):"WeakMap"===r?new WeakMap([...e]):"Error"===r?new Error(e.message):e},getEl=(e,t=document.body)=>{let r=getDataType(e),n=getDataType(t).includes("HTML")?t:document.querySelector(t),o=n&&n instanceof HTMLTemplateElement?n.content:n,a=null;if(e)if(r.includes("HTML"))a=e;else if("String"===r)try{a=(o||document).querySelector(e.trim())}catch{a=null}return a},createEl=(e,t,r)=>{let n=(e=e||"div").toUpperCase().trim(),o=document.createElement(n),a=getDataType(t);if(t&&"Object"===a)for(let e in t)t.hasOwnProperty(e)&&o.setAttribute(e,"string"==typeof t[e]?t[e]:JSON.stringify(t[e]));return((e,t)=>{if(""===t||null==t)return!1;let r=getDataType(t);if("TEMPLATE"===n)e.innerHTML=t.toString();else if("Array"===r&&t.length>0)for(let r of t){if(getDataType(r).includes("HTML"))e.appendChild(r);else{let t=createEl(r.name,r.attrs,r.content);t&&e.appendChild(t)}}else if(r.includes("HTML"))e.appendChild(t);else if("String"===r&&t.trim().startsWith("#")&&t.trim().length>1){let r=getEl(t);if(!r)return;"TEMPLATE"===r.nodeName?e.appendChild(r.content.cloneNode(!0)):e.insertAdjacentHTML("beforeEnd",r.innerHTML)}else e.insertAdjacentHTML("beforeEnd",t)})(o,r),o};return{getDataType:getDataType,requireTypes:(e,t,r)=>{let n=Array.isArray(t)?t:[t],o=getDataType(e),a=o.toLowerCase(),s=n.map(e=>e.toLowerCase()),i=a.includes("html")?"element":a;if(r)try{if(!s.includes(i))throw new TypeError(`Expected data type(s): [${s.join(", ")}], but got: ${i}`)}catch(e){r(e,o)}else if(!s.includes(i))throw new TypeError(`Expected data type(s): [${s.join(", ")}], but got: ${i}`);return o},deepClone:deepClone,deepCloneToJSON:deepCloneToJSON,wrapArrayMethods:({target:t,onBeforeMutate:r=()=>{},onAfterMutate:n=()=>{},allowList:o,props:a={}})=>{if(!Array.isArray(t))throw new TypeError("The 'target' parameter must be an array.");o&&!o?.length||(o=e);const s={};for(let e of o)s[e]=function(...o){const s={},i=t.length;switch(e){case"push":case"unshift":s.addedItems=[...o];break;case"pop":s.poppedItem=t[i-1];break;case"shift":s.shiftedItem=t[0];break;case"splice":const[e,r]=o,n=e<0?Math.max(i+e,0):Math.min(e,i),a=void 0===r?i-n:r;s.deletedItems=t.slice(n,n+a);break;case"sort":case"reverse":s.oldSnapshot=[...t];break;case"fill":case"copyWithin":const l=o[1]||0,c=void 0===o[2]?i:o[2];s.oldItems=t.slice(l,c),s.start=l,s.end=c}r?.(s);const l=Array.prototype[e].apply(t,o),c={value:l,key:e,args:o,context:s,target:t,...a};return n?.(c),l};return s},arrayMutableMethods:e,setMutableMethods:t,mapMutableMethods:r,wrapSetMethods:({target:e,onBeforeMutate:r=()=>{},onAfterMutate:n=()=>{},allowList:o=t,props:a={}})=>{if(!(e instanceof Set))throw new TypeError("The 'target' parameter must be a Set.");const s={},createWrappedMethod=t=>function(...o){const s={};switch(t){case"add":{const[t]=o;s.addedItem=t,s.existed=e.has(t);break}case"delete":{const[t]=o;s.existed=e.has(t),s.deletedItem=s.existed?t:void 0;break}case"clear":s.clearedItems=Array.from(e),s.previousSize=e.size}r(s);const i=e[t].apply(e,o),l={method:t,result:i,args:o,context:s,target:e,...a};return n(l),i};for(const e of o)t.includes(e)&&(s[e]=createWrappedMethod(e));return Object.defineProperty(s,"target",{get:()=>e,enumerable:!1,configurable:!1}),s},wrapMapMethods:({target:e,onBeforeMutate:t=()=>{},onAfterMutate:n=()=>{},allowList:o=r,props:a={}})=>{if(!(e instanceof Map))throw new TypeError("The 'target' parameter must be a Map.");const s={},createWrappedMethod=r=>function(...o){const s={};switch(r){case"set":{const[t,r]=o;s.key=t,s.newValue=r,s.existed=e.has(t),s.oldValue=s.existed?e.get(t):void 0;break}case"delete":{const[t]=o;s.key=t,s.existed=e.has(t),s.value=s.existed?e.get(t):void 0;break}case"clear":s.clearedItems=Array.from(e.entries()),s.previousSize=e.size}t(s);const i=e[r].apply(e,o),l={method:r,result:i,args:o,context:s,target:e,...a};return n(l),i};for(const e of o)r.includes(e)&&(s[e]=createWrappedMethod(e));return Object.defineProperty(s,"target",{get:()=>e,enumerable:!1,configurable:!1}),s},getUniqueId:(e={})=>{const t=e.prefix,r=e.suffix,n=e.base10,o=e.base36;return`${t?t+"-":""}${Date.now()}${o?"-"+Math.random().toString(36).substring(2,11):""}${n?"-"+Math.floor(1e4*Math.random()).toString().padStart(4,"0"):""}${r?"-"+r:""}`},deepMerge:(e,t,r={})=>{const n=Object.assign({dataMode:"clear",inheritMissing:!0,targetClone:!1,useEnable:!0,useSymbol:!0,nullBehavior:"preserve",undefinedBehavior:"preserve",deepClone:{},onBeforeMerge:void 0,onAfterMerge:void 0},r),smartMerger=(e,t,n)=>{let o,a,s=getDataType(e),i=getDataType(t),l=!0;if(n.interceptor&&"function"==typeof n.interceptor){let r=n.interceptor({target:e,source:t,targetType:s,sourceType:i,parent:n.parent});if(r){if(null===r?.target||null===r?.source)return r;e=r.target,t=r.source}}return n?.onBeforeMerge?.({target:e,source:t,targetType:s,sourceType:i,parent:n.parent}),"Object"===s&&"Object"===i?(a=deepMergeObjects(e,t,n),o="Object"):"Array"===s&&"Array"===i?(a=deepMergeArrays(e,t,n),o="Array"):"Set"===s&&"Set"===i?(a=deepMergeSets(e,t,n),o="Set"):"Map"===s&&"Map"===i?(a=deepMergeMaps(e,t,n),o="Map"):(l=!1,a=e),n?.onAfterMerge?.({result:a,target:e,source:t,targetType:s,sourceType:i,mergeType:o,parent:r.parent}),{result:a,flag:l,mergeType:o}},mergeEnableObject=(e,t)=>e?.hasOwnProperty("enable")&&"boolean"==typeof t?(e.enable=t,e):t?.hasOwnProperty("enable")&&"boolean"==typeof e?Object.assign({enable:e},t):t,deepMergeObjects=(e,t,r={})=>{let n=getDataType(e),o=getDataType(t);if("Object"!==n||"Object"!==o)return e;const a=Object.assign({inheritMissing:!0,targetClone:!1,useEnable:!0},r);let s={};s=a.targetClone?shallowCopy(e):e;for(let e in t){const n=s[e],o=t[e];if(t.hasOwnProperty(e)&&s.hasOwnProperty(e)){const t=smartMerger(n,o,{...r,parent:s});if(t.flag)t.mergeType?"Object"===t.mergeType&&(s[e]=t.result):s[e]=o;else{let t=a.useEnable?mergeEnableObject(n,o):o;n!==t&&null===t?"ignore"===a.nullBehavior||("delete"===a.nullBehavior?Reflect.deleteProperty(s,e):s[e]=t):n!==t&&void 0===t?"ignore"===a.undefinedBehavior||("delete"===a.undefinedBehavior?Reflect.deleteProperty(s,e):s[e]=o):s[e]=o}}else t.hasOwnProperty(e)&&!s.hasOwnProperty(e)&&a.inheritMissing&&(s[e]=o)}if(a.useSymbol){let e=Object.getOwnPropertySymbols(t);if(e.length)for(let r of e)s[r]=t[r]}return s},deepMergeArrays=(e,t,r={})=>{if(!Array.isArray(e)||!Array.isArray(t))return e;const n=Object.assign({dataMode:"clear",inheritMissing:!0,targetClone:!1},r),o=n.targetClone?[...e]:e;if("replace"===n.dataMode)for(let e=0;e<t.length&&(n.inheritMissing||!(e>=o.length));e++){smartMerger(o[e],t[e],{...n,parent:o}).flag||(o[e]=t[e])}else"concat"===n.dataMode||(o.length=0),o.push(...t);return o},deepMergeMaps=(e,t,r={})=>{if(!(e instanceof Map&&t instanceof Map))return e;const n=Object.assign({inheritMissing:!0,targetClone:!1,useEnable:!0},r),o=n.targetClone?new Map([...e]):e;for(const[e,a]of t.entries())if(o.has(e)){const t=o.get(e),r=a,s=smartMerger(t,r,n);s.flag?"Object"===s.mergeType&&o.set(e,s.result):o.set(e,r)}else r.inheritMissing&&o.set(e,a);return o},deepMergeSets=(e,t,r={})=>{if(!(e instanceof Set&&t instanceof Set))return e;const n=Object.assign({dataMode:"clear",inheritMissing:!0,targetClone:!1,useEnable:!0},r),o=n.targetClone?new Set(...e):e;if("replace"===n.dataMode){const e=[...o],r=[...t],a=smartMerger(e,r,n);o.clear();for(let e of a.result)o.add(e)}else if("concat"===n.dataMode)for(let e of t)o.add(e);else{o.clear();for(let e of t)o.add(e)}return o};return smartMerger(e,t,n).result},shallowCopy:shallowCopy,copyObjectWithSymbol:copyObjectWithSymbol,getEl:getEl,getEls:(e,t=document.body)=>{let r=getDataType(e),n=getEl(t),o=n&&n instanceof HTMLTemplateElement?n.content:n||document,a=[];return(e=>{let t,r=getDataType(e);return t=!e||("Object"===r?0===Object.keys(e).length:"Array"===r?""===e.join(""):"Function"===r?"{}"===e.toString().replace(/\s+/g,"").match(/{.*}/g)[0]:"Symbol"===r?"()"===e.toString().replace(/\s+/g,"").match(/\(.*\)/g)[0]:"Set"===r||"Map"===r?0===e.size:"Date"===r?isNaN(e.getTime()):"RegExp"===r?""===e.source:"ArrayBuffer"===r?0===e.byteLength:"NodeList"===r||"HTMLCollection"===r||"length"in e&&"number"==typeof e.length?0===e.length:"size"in e&&"number"==typeof e.size?0===e.size:"Error"===r||e instanceof Error?""===e.message:!(!r.includes("Array")||!["Uint8Array","Int8Array","Uint16Array","Int16Array","Uint32Array","Int32Array","Float32Array","Float64Array"].includes(r))&&0===e.length),t})(e)?a:(r.includes("HTML")?a.push(e):"String"===r?a=(e=e.trim()).split(",").map(e=>[...o.querySelectorAll(e)]).flat():"Array"===r&&(a=e.map(e=>getEl(e,n))),a.filter(Boolean))},createEl:createEl}});
package/dist.zip CHANGED
Binary file
package/modules.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Last modified: 2025/12/25 14:29:40
2
+ * Last modified: 2026/01/05 10:31:32
3
3
  */
4
4
  'use strict';
5
5
  import deepClone from './src/deepClone';
@@ -16,6 +16,9 @@ import wrapMapMethods from './src/wrapMapMethods';
16
16
  import deepMerge from './src/deepMerge';
17
17
  import shallowCopy from './src/shallowCopy';
18
18
  import copyObjectWithSymbol from './src/copyObjectWithSymbol';
19
+ import getEl from './src/getEl';
20
+ import getEls from './src/getEls';
21
+ import createEl from './src/createEl';
19
22
  const utils = {
20
23
  //executeStr,
21
24
  getDataType,
@@ -34,5 +37,8 @@ const utils = {
34
37
  deepMerge,
35
38
  shallowCopy,
36
39
  copyObjectWithSymbol,
40
+ getEl,
41
+ getEls,
42
+ createEl,
37
43
  };
38
44
  export default utils;
package/modules.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Last modified: 2025/12/25 14:29:40
2
+ * Last modified: 2026/01/05 10:31:32
3
3
  */
4
4
  'use strict'
5
5
  import deepClone from './src/deepClone';
@@ -24,6 +24,9 @@ import deepMergeSets from './src/deepMergeSets';
24
24
  import deepEqual from './src/deepEqual';
25
25
  import shallowCopy from './src/shallowCopy';
26
26
  import copyObjectWithSymbol from './src/copyObjectWithSymbol';
27
+ import getEl from './src/getEl';
28
+ import getEls from './src/getEls';
29
+ import createEl from './src/createEl';
27
30
 
28
31
 
29
32
 
@@ -45,6 +48,9 @@ const utils = {
45
48
  deepMerge,
46
49
  shallowCopy,
47
50
  copyObjectWithSymbol,
51
+ getEl,
52
+ getEls,
53
+ createEl,
48
54
 
49
55
  };
50
56
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codady/utils",
3
- "version": "0.0.17",
3
+ "version": "0.0.19",
4
4
  "author": "AXUI Development Team",
5
5
  "license": "MIT",
6
6
  "description": "This is a set of general-purpose JavaScript utility functions developed by the AXUI team. All functions are pure and do not involve CSS or other third-party libraries. They are suitable for any web front-end environment.",
@@ -0,0 +1,83 @@
1
+ /**
2
+ * @since Last modified: 2026/01/05 10:30:46
3
+ * @function createEl
4
+ * @description Create a node or a group of father-son nodes.
5
+ * @param {string} name="div" - Node name, requierd.
6
+ * @param {object} [attrs] - Node attributes.Format : {class:'demo',style:'width:100px;height:50px;',disabled:''}
7
+ * @param {string|number|array} [content] - Node content.If it is an array,create a sub-node of the cycle.
8
+ * @returns {HTMLElement|null} Return a node or null
9
+ * @example
10
+ * ax.createEl('div',{class:'demo'},'I love you');
11
+ * <!--return a HTMLElement node-->
12
+ */
13
+ //简介:创建一个节点或一组父子节点
14
+ //参数name:节点名称,不可为空
15
+ //参数attrs:节点上的属性,键值对的对象格式
16
+ //参数content:节点内容,如果是数组,那么将创建子节点
17
+ //返回:一个节点或null
18
+ 'use strict';
19
+ import getDataType from './getDataType';
20
+ import getEl from './getEl';
21
+ const createEl = (name, attrs, content) => {
22
+ //默认为div
23
+ name = name || 'div';
24
+ //统一大小写
25
+ let rootName = name.toUpperCase().trim(), rootEl = document.createElement(rootName), attrsType = getDataType(attrs), loop = (host, data) => {
26
+ if (data === '' || data === null || data === undefined) {
27
+ //为空、未定义则不再执行
28
+ return false;
29
+ }
30
+ let dataType = getDataType(data);
31
+ //template是DocumentFragment类型不能用insertAdjacentHTML
32
+ if (rootName === 'TEMPLATE') {
33
+ host.innerHTML = data.toString();
34
+ }
35
+ else {
36
+ if (dataType === 'Array' && data.length > 0) {
37
+ //节点数组
38
+ //data.forEach((i: T_obj) => loop(el, i));
39
+ for (let k of data) {
40
+ let childType = getDataType(k);
41
+ if (childType.includes('HTML')) {
42
+ //是个节点
43
+ host.appendChild(k);
44
+ }
45
+ else {
46
+ //是个对象{name:'',attrs:{},content:''}
47
+ let child = createEl(k.name, k.attrs, k.content);
48
+ child && host.appendChild(child);
49
+ }
50
+ }
51
+ }
52
+ else if (dataType.includes('HTML')) {
53
+ //HTML节点
54
+ host.appendChild(data);
55
+ }
56
+ else if (dataType === 'String' && data.trim().startsWith('#') && data.trim().length > 1) {
57
+ //是字符串且是#id选择器,则取其文本
58
+ let el = getEl(data);
59
+ if (!el)
60
+ return;
61
+ //如果是template模板节点则需要特殊处理
62
+ el.nodeName === 'TEMPLATE' ? host.appendChild(el.content.cloneNode(true)) : host.insertAdjacentHTML('beforeEnd', el.innerHTML);
63
+ }
64
+ else {
65
+ //字符串数字等
66
+ host.insertAdjacentHTML('beforeEnd', data);
67
+ }
68
+ }
69
+ };
70
+ //添加属性
71
+ if (attrs && attrsType === 'Object') {
72
+ for (let k in attrs) {
73
+ //注意,attrs[k]可能是一个{}或[],不一定是字符串
74
+ // JSON.stringify可以将所有格式的数据都转成文本,会忽略函数和节点数据
75
+ //字符串则不需要stringify,否则会将字符串的引号也一并输出
76
+ attrs.hasOwnProperty(k) && rootEl.setAttribute(k, typeof attrs[k] === 'string' ? attrs[k] : JSON.stringify(attrs[k]));
77
+ }
78
+ }
79
+ //执行循环创建子节点
80
+ loop(rootEl, content);
81
+ return rootEl;
82
+ };
83
+ export default createEl;
@@ -0,0 +1,80 @@
1
+ /**
2
+ * @since Last modified: 2026/01/05 10:30:46
3
+ * @function createEl
4
+ * @description Create a node or a group of father-son nodes.
5
+ * @param {string} name="div" - Node name, requierd.
6
+ * @param {object} [attrs] - Node attributes.Format : {class:'demo',style:'width:100px;height:50px;',disabled:''}
7
+ * @param {string|number|array} [content] - Node content.If it is an array,create a sub-node of the cycle.
8
+ * @returns {HTMLElement|null} Return a node or null
9
+ * @example
10
+ * ax.createEl('div',{class:'demo'},'I love you');
11
+ * <!--return a HTMLElement node-->
12
+ */
13
+ //简介:创建一个节点或一组父子节点
14
+ //参数name:节点名称,不可为空
15
+ //参数attrs:节点上的属性,键值对的对象格式
16
+ //参数content:节点内容,如果是数组,那么将创建子节点
17
+ //返回:一个节点或null
18
+ 'use strict';
19
+ import getDataType from './getDataType';
20
+ import getEl from './getEl';
21
+ const createEl = (name: string, attrs?: Record<string,any> | null, content?: any) => {
22
+ //默认为div
23
+ name = name || 'div';
24
+ //统一大小写
25
+ let rootName = name.toUpperCase().trim(),
26
+ rootEl = document.createElement(rootName),
27
+ attrsType = getDataType(attrs),
28
+ loop = (host: any, data: any) => {
29
+ if (data === '' || data === null || data === undefined) {
30
+ //为空、未定义则不再执行
31
+ return false;
32
+ }
33
+ let dataType = getDataType(data);
34
+ //template是DocumentFragment类型不能用insertAdjacentHTML
35
+ if (rootName === 'TEMPLATE') {
36
+ host.innerHTML = data.toString();
37
+ } else {
38
+ if (dataType === 'Array' && data.length > 0) {
39
+ //节点数组
40
+ //data.forEach((i: T_obj) => loop(el, i));
41
+ for (let k of data) {
42
+ let childType = getDataType(k);
43
+ if (childType.includes('HTML')) {
44
+ //是个节点
45
+ host.appendChild(k);
46
+ } else {
47
+ //是个对象{name:'',attrs:{},content:''}
48
+ let child = createEl(k.name, k.attrs, k.content);
49
+ child && host.appendChild(child);
50
+ }
51
+ }
52
+ } else if (dataType.includes('HTML')) {
53
+ //HTML节点
54
+ host.appendChild(data);
55
+ } else if (dataType === 'String' && data.trim().startsWith('#') && data.trim().length > 1) {
56
+ //是字符串且是#id选择器,则取其文本
57
+ let el = getEl(data);
58
+ if (!el) return;
59
+ //如果是template模板节点则需要特殊处理
60
+ el.nodeName === 'TEMPLATE' ? host.appendChild((el as any).content.cloneNode(true)) : host.insertAdjacentHTML('beforeEnd',(el as any).innerHTML);
61
+ } else {
62
+ //字符串数字等
63
+ host.insertAdjacentHTML('beforeEnd', data);
64
+ }
65
+ }
66
+ }
67
+ //添加属性
68
+ if (attrs && attrsType === 'Object') {
69
+ for (let k in attrs) {
70
+ //注意,attrs[k]可能是一个{}或[],不一定是字符串
71
+ // JSON.stringify可以将所有格式的数据都转成文本,会忽略函数和节点数据
72
+ //字符串则不需要stringify,否则会将字符串的引号也一并输出
73
+ attrs.hasOwnProperty(k) && rootEl.setAttribute(k, typeof attrs[k] === 'string' ? attrs[k] : JSON.stringify(attrs[k]));
74
+ }
75
+ }
76
+ //执行循环创建子节点
77
+ loop(rootEl, content);
78
+ return rootEl;
79
+ }
80
+ export default createEl;
package/src/deepClone.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @since Last modified: 2025/12/26 15:13:54
2
+ * @since Last modified: 2025/12/27 14:34:57
3
3
  * Deep clone an array, object, or other cloneable data types.
4
4
  *
5
5
  * Features:
package/src/deepClone.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @since Last modified: 2025/12/26 15:13:54
2
+ * @since Last modified: 2025/12/27 14:34:57
3
3
  * Deep clone an array, object, or other cloneable data types.
4
4
  *
5
5
  * Features:
package/src/deepMerge.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @since Last modified: 2025/12/26 16:03:37
2
+ * @since Last modified: 2025/12/27 14:35:01
3
3
  * @function deepMerge
4
4
  * @description Deeply merges two data structures (Object, Array, Map, or Set) based on their types.
5
5
  * This function recursively merges the properties or items of the target and source, depending on their types.
@@ -57,6 +57,8 @@ const deepMerge = (target, source, opts = {}) => {
57
57
  // Whether to allow merging key=symbol key-value pairs when target is {} type.
58
58
  // target是{}类型时,是否允许合并key=symbol的键值对。
59
59
  useSymbol: true,
60
+ nullBehavior: 'preserve',
61
+ undefinedBehavior: 'preserve',
60
62
  // Options passed to the deepClone function when targetClone is true
61
63
  // 当targetClone为true时传递给deepClone函数的选项
62
64
  deepClone: {},
@@ -145,18 +147,42 @@ const deepMerge = (target, source, opts = {}) => {
145
147
  // 如果是复制方法,则先复制target
146
148
  result = options.targetClone ? shallowCopy(target) : target;
147
149
  for (let k in source) {
150
+ const _result = result[k], _source = source[k];
148
151
  if (source.hasOwnProperty(k) && result.hasOwnProperty(k)) {
149
- let resp = smartMerger(result[k], source[k], { ...opts, parent: result });
152
+ const resp = smartMerger(_result, _source, { ...opts, parent: result });
150
153
  //resp={result,flag,type}
151
- //flag=true表示类型一致并完成了合并,false表示并没有合并需要直接赋值
154
+ //flag=true表示类型一致(object/array/map/set)并完成了合并,false表示并没有合并需要直接赋值
152
155
  if (!resp.flag) {
153
156
  //类型不同则直接覆盖
154
- if (options.useEnable) {
155
- result[k] = mergeEnableObject(result[k], source[k]);
157
+ let tmp = options.useEnable ? mergeEnableObject(_result, _source) : _source;
158
+ if (_result !== tmp && tmp === null) {
159
+ if (options.nullBehavior === 'ignore') {
160
+ //不处理
161
+ }
162
+ else if (options.nullBehavior === 'delete') {
163
+ //删除属性
164
+ Reflect.deleteProperty(result, k);
165
+ }
166
+ else {
167
+ //替换
168
+ result[k] = tmp;
169
+ }
170
+ }
171
+ else if (_result !== tmp && tmp === undefined) {
172
+ if (options.undefinedBehavior === 'ignore') {
173
+ //不处理
174
+ }
175
+ else if (options.undefinedBehavior === 'delete') {
176
+ //删除属性
177
+ Reflect.deleteProperty(result, k);
178
+ }
179
+ else {
180
+ //替换
181
+ result[k] = _source;
182
+ }
156
183
  }
157
184
  else {
158
- //完全替换
159
- result[k] = source[k];
185
+ result[k] = _source;
160
186
  }
161
187
  }
162
188
  else {
@@ -169,13 +195,13 @@ const deepMerge = (target, source, opts = {}) => {
169
195
  }
170
196
  else {
171
197
  //其他类型则直接覆盖
172
- result[k] = source[k];
198
+ result[k] = _source;
173
199
  }
174
200
  }
175
201
  }
176
202
  else if (source.hasOwnProperty(k) && !result.hasOwnProperty(k) && options.inheritMissing) {
177
203
  //如果source有属性,result没有该属性,但是options允许追加属性则直接赋值
178
- result[k] = source[k];
204
+ result[k] = _source;
179
205
  }
180
206
  }
181
207
  //Symbol键直接追加,因为Symbol是唯一,结果同Object.assign