123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182 |
- const toString = Object.prototype.toString
- function __type(x) {
- // fix typeof null = object
- if (x === null) {
- return 'null'
- }
- const t = typeof x
- if (t !== 'object') {
- return t
- }
- let cls
- let clsLow
- try {
- cls = toString.call(x).slice(8, -1)
- clsLow = cls.toLowerCase()
- } catch (e) {
- // ie下的 activex对象
- return 'object'
- }
- if (clsLow !== 'object') {
- return clsLow
- }
- if (x.constructor === Object) {
- return clsLow
- }
- // Object.create(null)
- try {
- /* eslint-disable no-proto */
- if (Object.getPrototypeOf(x) === null || x.__proto__ === null) {
- /* eslint-enable no-proto */
- return 'object'
- }
- } catch (e) {
- //
- }
- try {
- const cname = x.constructor.name
- if (typeof cname === 'string') {
- return cname
- }
- } catch (e) {
- // 无constructor
- }
- // function A() {}; A.prototype.constructor = null; new A
- return 'unknown'
- }
- function SimpleWeakmap() {
- this.cacheArray = []
- }
- const UNIQUE_KEY = `com.yanhaijing.jsmini.clone${(new Date()).getTime()}`
- SimpleWeakmap.prototype.set = function(key, value) {
- this.cacheArray.push(key)
- key[UNIQUE_KEY] = value
- }
- SimpleWeakmap.prototype.get = function(key) {
- return key[UNIQUE_KEY]
- }
- SimpleWeakmap.prototype.clear = function() {
- for (let i = 0; i < this.cacheArray.length; i++) {
- const key = this.cacheArray[i]
- delete key[UNIQUE_KEY]
- }
- this.cacheArray.length = 0
- }
- function getWeakMap() {
- let result
- if (typeof WeakMap !== 'undefined' && __type(WeakMap) === 'function') {
- result = new WeakMap()
- if (__type(result) === 'weakmap') {
- return result
- }
- }
- result = new SimpleWeakmap()
- return result
- }
- function isClone(x) {
- const t = __type(x)
- return t === 'object' || t === 'array'
- }
- function hasOwnProp(obj, key) {
- return Object.prototype.hasOwnProperty.call(obj, key)
- }
- function copy(x) {
- const uniqueData = getWeakMap()
- const t = __type(x)
- let root = x
- if (t === 'array') {
- root = []
- } else if (t === 'object') {
- root = {}
- }
- // 循环数组
- const loopList = [
- {
- parent: root,
- key: undefined,
- data: x,
- }
- ]
- while (loopList.length) {
- // 深度优先
- const node = loopList.pop()
- const parent = node.parent
- const key = node.key
- const source = node.data
- const tt = __type(source)
- // 初始化赋值目标,key为undefined则拷贝到父元素,否则拷贝到子元素
- let target = parent
- if (typeof key !== 'undefined') {
- parent[key] = tt === 'array' ? [] : {}
- target = parent[key]
- }
- // 复杂数据需要缓存操作
- if (isClone(source)) {
- // 命中缓存,直接返回缓存数据
- const uniqueTarget = uniqueData.get(source)
- if (uniqueTarget) {
- parent[key] = uniqueTarget
- continue // 中断本次循环
- }
- // 未命中缓存,保存到缓存
- uniqueData.set(source, target)
- }
- if (tt === 'array') {
- for (let i = 0; i < source.length; i++) {
- if (isClone(source[i])) {
- // 下一次循环
- loopList.push({
- parent: target,
- key: i,
- data: source[i],
- })
- } else {
- target[i] = source[i]
- }
- }
- } else if (tt === 'object') {
- for (const k in source) {
- if (hasOwnProp(source, k)) {
- if (k === UNIQUE_KEY) { continue }
- if (isClone(source[k])) {
- // 下一次循环
- loopList.push({
- parent: target,
- key: k,
- data: source[k],
- })
- } else {
- target[k] = source[k]
- }
- }
- }
- }
- }
-
- uniqueData.clear && uniqueData.clear()
-
- return root
- }
- module.exports = {
- copy,
- }
|