|
1 | 1 | /**
|
2 |
| -* Copyright (c) 2023 - present TinyEngine Authors. |
3 |
| -* Copyright (c) 2023 - present Huawei Cloud Computing Technologies Co., Ltd. |
4 |
| -* |
5 |
| -* Use of this source code is governed by an MIT-style license. |
6 |
| -* |
7 |
| -* THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, |
8 |
| -* BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR |
9 |
| -* A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. |
10 |
| -* |
11 |
| -*/ |
| 2 | + * Copyright (c) 2023 - present TinyEngine Authors. |
| 3 | + * Copyright (c) 2023 - present Huawei Cloud Computing Technologies Co., Ltd. |
| 4 | + * |
| 5 | + * Use of this source code is governed by an MIT-style license. |
| 6 | + * |
| 7 | + * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, |
| 8 | + * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR |
| 9 | + * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. |
| 10 | + * |
| 11 | + */ |
12 | 12 |
|
| 13 | +import { isRef, isProxy, unref, toRaw } from 'vue' |
13 | 14 | import { isObject, isArray } from '@opentiny/vue-renderless/grid/static'
|
14 | 15 |
|
15 | 16 | export const fun_ctor = Function
|
@@ -177,3 +178,149 @@ export function generateRandomLetters(length = 1) {
|
177 | 178 | }
|
178 | 179 | return result
|
179 | 180 | }
|
| 181 | + |
| 182 | +export function getRawValue(target) { |
| 183 | + let res = target |
| 184 | + |
| 185 | + if (isRef(res)) { |
| 186 | + res = unref(res) |
| 187 | + } |
| 188 | + |
| 189 | + if (isProxy(res)) { |
| 190 | + return toRaw(res) |
| 191 | + } |
| 192 | + |
| 193 | + return res |
| 194 | +} |
| 195 | + |
| 196 | +export function getType(val) { |
| 197 | + let type = typeof val |
| 198 | + |
| 199 | + if (type !== 'object') { |
| 200 | + return type |
| 201 | + } |
| 202 | + |
| 203 | + return Object.prototype.toString.call(val).replace(/\[object (.*)\]/, '$1') |
| 204 | +} |
| 205 | + |
| 206 | +function cloneArray(target, map, _deepClone) { |
| 207 | + let res = [] |
| 208 | + |
| 209 | + map.set(target, res) |
| 210 | + |
| 211 | + target.forEach((item, index) => { |
| 212 | + res[index] = _deepClone(item, map) |
| 213 | + }) |
| 214 | + |
| 215 | + return res |
| 216 | +} |
| 217 | + |
| 218 | +function cloneMap(target, map, _deepClone) { |
| 219 | + let res = new Map() |
| 220 | + |
| 221 | + map.set(target, res) |
| 222 | + |
| 223 | + target.forEach((value, key) => { |
| 224 | + res.set(key, _deepClone(value, map)) |
| 225 | + }) |
| 226 | + |
| 227 | + return res |
| 228 | +} |
| 229 | + |
| 230 | +function cloneSet(target, map, _deepClone) { |
| 231 | + let res = new Set() |
| 232 | + |
| 233 | + map.set(target, res) |
| 234 | + |
| 235 | + target.forEach((value) => { |
| 236 | + res.add(_deepClone(value, map)) |
| 237 | + }) |
| 238 | + |
| 239 | + return res |
| 240 | +} |
| 241 | + |
| 242 | +function cloneObject(target, map, _deepClone) { |
| 243 | + const res = {} |
| 244 | + |
| 245 | + map.set(target, res) |
| 246 | + |
| 247 | + Object.entries(target).forEach(([key, value]) => { |
| 248 | + res[key] = _deepClone(value, map) |
| 249 | + }) |
| 250 | + |
| 251 | + return res |
| 252 | +} |
| 253 | + |
| 254 | +export function naiveDeepClone(target) { |
| 255 | + try { |
| 256 | + return structuredClone(target) |
| 257 | + } catch (error) { |
| 258 | + // target is no serializable |
| 259 | + } |
| 260 | +} |
| 261 | + |
| 262 | +/** |
| 263 | + * 使用 JSON.stringify 进行 deep clone |
| 264 | + * 不支持 Map、Set、Date、RegExp、ArrayBuffer 等变量类型 |
| 265 | + * 不支持循环引用 |
| 266 | + * @param {*} target target to be copy |
| 267 | + * @param {*} callback target copyed |
| 268 | + */ |
| 269 | +export function jsonDeepClone(target, callback) { |
| 270 | + try { |
| 271 | + JSON.parse(JSON.stringify(target)) |
| 272 | + } catch (error) { |
| 273 | + if (typeof callback === 'function') { |
| 274 | + callback() |
| 275 | + } |
| 276 | + } |
| 277 | +} |
| 278 | + |
| 279 | +const copyMethodMap = { |
| 280 | + Array: cloneArray, |
| 281 | + Map: cloneMap, |
| 282 | + Set: cloneSet, |
| 283 | + Object: cloneObject |
| 284 | +} |
| 285 | + |
| 286 | +function _deepClone(target, map) { |
| 287 | + if (map.has(target)) { |
| 288 | + return map.get(target) |
| 289 | + } |
| 290 | + |
| 291 | + const copyTarget = getRawValue(target) |
| 292 | + const basicType = ['undefined', 'number', 'string', 'boolean', 'function', 'bigint', 'symbol', 'Null'] |
| 293 | + |
| 294 | + let type = getType(copyTarget) |
| 295 | + |
| 296 | + if (basicType.includes(type)) { |
| 297 | + return target |
| 298 | + } |
| 299 | + |
| 300 | + let res = naiveDeepClone(copyTarget) |
| 301 | + |
| 302 | + if (res) { |
| 303 | + map.set(target, res) |
| 304 | + |
| 305 | + return res |
| 306 | + } |
| 307 | + |
| 308 | + if (copyMethodMap[type]) { |
| 309 | + res = copyMethodMap[type](target, map, _deepClone) |
| 310 | + |
| 311 | + return res |
| 312 | + } |
| 313 | + |
| 314 | + return copyTarget |
| 315 | +} |
| 316 | + |
| 317 | +/** |
| 318 | + * 优先使用 structuredClone 的深拷贝方法 |
| 319 | + * 不支持 拷贝 prototype、function、DOM nodes、proxy(getter、setter) |
| 320 | + * 如果是 vue 的 ref 或者 reactive,会尝试拿到 raw value 然后进行深拷贝 |
| 321 | + * @param {*} target value to be deep clone |
| 322 | + * @returns * deepCloned target |
| 323 | + */ |
| 324 | +export function deepClone(target) { |
| 325 | + return _deepClone(target, new WeakMap()) |
| 326 | +} |
0 commit comments