From 9ba807fcb1c89fcb2267f9b6205aef9b6a2ef534 Mon Sep 17 00:00:00 2001 From: wanghaoran5 Date: Thu, 25 Oct 2018 20:04:05 +0800 Subject: [PATCH 1/4] =?UTF-8?q?=E5=AE=8C=E6=88=90Set=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E7=9A=84clone?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/index.js | 145 ++++++++++++++++++++++++++++++++++-------------- test/test.js | 152 ++++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 248 insertions(+), 49 deletions(-) diff --git a/src/index.js b/src/index.js index c84a844..219dfcc 100644 --- a/src/index.js +++ b/src/index.js @@ -1,5 +1,6 @@ import { type } from '@jsmini/type'; + // Object.create(null) 的对象,没有hasOwnProperty方法 function hasOwnProp(obj, key) { return Object.prototype.hasOwnProperty.call(obj, key); @@ -8,7 +9,7 @@ function hasOwnProp(obj, key) { // 仅对对象和数组进行深拷贝,其他类型,直接返回 function isClone(x) { const t = type(x); - return t === 'object' || t === 'array'; + return t === 'object' || t === 'array' || t === 'set' || t === 'map'; } // 递归 @@ -130,6 +131,7 @@ export function cloneLoop(x) { } const UNIQUE_KEY = 'com.yanhaijing.jsmini.clone' + (new Date).getTime(); +const UNIQUE_SET_KEY = 'com.yanhaijing.jsmini.clone.set' + (new Date).getTime(); // weakmap:处理对象关联引用 function SimpleWeakmap (){ @@ -164,24 +166,76 @@ function getWeakMap(){ return result; } -export function cloneForce(x) { - const uniqueData = getWeakMap(); +function setValueToParent(parent,key,value){ + key == UNIQUE_SET_KEY ? parent.add(value) : parent[key] = value; + return value; +} - const t = type(x); +/** + * + * @param {function} fn 被执行的函数 + * + * 返回一个函数a,该函数a会缓存fn的执行结果 + */ +function runOnce(fn){ + let result; + let time = 0; + return function(){ + if(time > 0){ + return result; + } + time++; + result = fn(); - let root = x; + return result; + }; +} - if (t === 'array') { - root = []; - } else if (t === 'object') { - root = {}; +//检测Set功能 +const checkSet = runOnce(function(){ + try { + let set = new Set(); + set.add(UNIQUE_KEY); + + if(set.has(UNIQUE_KEY)){ + + set.delete(UNIQUE_KEY); + return true; + } + } catch (e) { + console.log(e.message); } + return false; +}); +//检测Map的功能 +const checkMap = runOnce(function(){ + try { + let map = new Map(); + map.set(UNIQUE_KEY,'Map'); + + if(map.has(UNIQUE_KEY) && map.get(UNIQUE_KEY) == 'Map'){ + + map.delete(UNIQUE_KEY); + return true; + } + } catch (e) { + console.log(e.message); + } + return false; +}); + +export function cloneForce(x) { + const uniqueData = getWeakMap(); + + let root = { + next:x + }; // 循环数组 const loopList = [ { parent: root, - key: undefined, + key: 'next', data: x, } ]; @@ -194,59 +248,66 @@ export function cloneForce(x) { const source = node.data; const tt = type(source); - // 初始化赋值目标,key为undefined则拷贝到父元素,否则拷贝到子元素 - let target = parent; - if (typeof key !== 'undefined') { - target = parent[key] = tt === 'array' ? [] : {}; - } - // 复杂数据需要缓存操作 if (isClone(source)) { // 命中缓存,直接返回缓存数据 let uniqueTarget = uniqueData.get(source); if (uniqueTarget) { - parent[key] = uniqueTarget; + setValueToParent(parent,key,uniqueTarget); continue; // 中断本次循环 } - - // 未命中缓存,保存到缓存 - uniqueData.set(source, target); } + let newValue; if (tt === 'array') { + newValue = setValueToParent(parent,key,[]); 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]; - } + // 下一次循环 + loopList.push({ + parent: newValue, + key: i, + data: source[i], + }); } } else if (tt === 'object'){ + newValue = setValueToParent(parent,key,{}); for(let k in source) { + if(k === UNIQUE_KEY) continue; 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]; - } + // 下一次循环 + loopList.push({ + parent: newValue, + key: k, + data: source[k], + }); } } + } else if (tt === 'set' && checkSet()){ + newValue = setValueToParent(parent,key,new Set()); + for (let s of source){ + // 下一次循环 + loopList.push({ + parent: newValue, + key: UNIQUE_SET_KEY, + data: s, + }); + } + } else if (tt === 'Map' && checkMap()){ + newValue = setValueToParent(parent,key,new Map()); + } else{ + setValueToParent(parent,key,source); + continue; } + + // 未命中缓存,保存到缓存 + uniqueData.set(source, newValue); + } uniqueData.clear && uniqueData.clear(); - return root; + return root.next; } + + diff --git a/test/test.js b/test/test.js index 9d8de9f..33cffca 100644 --- a/test/test.js +++ b/test/test.js @@ -1,4 +1,5 @@ var expect = require('expect.js'); +var type = require('@jsmini/type').type; var clone = require('../dist/index.js').clone; var cloneJSON = require('../dist/index.js').cloneJSON; @@ -28,6 +29,8 @@ describe('单元测试', function() { } ]; + + // 正常cases var normalList = [ { @@ -53,6 +56,54 @@ describe('单元测试', function() { } ]; + //添加set数据 + try { + var normalList1 = [ + { + a: [], + }, + { + a: [1, 2, 3], + }, + { + a: [1, [2, [3]]], + }, + { + a: {}, + }, + { + a: {a: 1, b: 2, c: 3}, + }, + { + a: {a1: 1, a2: {b1: 1, b2: {c1: 1, c2: 2}}}, + }, + { + a: {a1: 1, a2: [1, {b1: 1, b2: [{c1: 1, c2: 2}]}]} + } + ]; + let set = new Set() + let set1 = new Set() + set.add(1) + set.add(set1) + set.add({ + a: 1, + a1:[set1], + a2:{ + a:[set1] + } + }) + set.add([ + 'abc' + ]) + set.add(null) + set.add(undefined) + normalList1.push({ + a:set, + }) + } catch (error) { + + } + // 父子循环引用 var a = [1, 2, 3]; a.push(a); @@ -71,6 +122,43 @@ describe('单元测试', function() { } ]; + //添加set数据 + try { + var singleRefList1 = [ + { + a: a, + }, + { + a: b, + }, + { + a: b, + } + ]; + let set = new Set() + let set1 = new Set() + set.add(1) + set.add(set1) + set1.add({ + a: 1, + a1:[set1], + a2:{ + a:[set1] + } + }) + set.add([ + 'abc' + ]) + set.add(null) + set.add(set1) + set1.add(set) + singleRefList.push({ + a:set, + }) + } catch (error) { + + } + // 多层级循环引用 var a = [1, [2]]; a[1].push(a); @@ -88,6 +176,38 @@ describe('单元测试', function() { a: b, } ]; + //添加set数据 + try { + var complexRefList1 = [ + { + a: a, + }, + { + a: b, + }, + { + a: b, + } + ]; + let set = new Set() + let set1 = new Set() + let set2 = new Set() + set.add(set) + + complexRefList1.push({ + a:set + }) + set1.add(set2) + set2.add({ + b:set1 + }) + set2.add(set1) + complexRefList1.push({ + a:set1 + }) + } catch (error) { + + } describe('clone', function() { it('常规', function() { for (var i = 0; i < simpleList.length; i++) { @@ -166,29 +286,47 @@ describe('单元测试', function() { } for (var i = 0; i < normalList.length; i++) { - var temp = cloneForce(normalList[i].a); + var temp = cloneForce(normalList1[i].a); // 确保不全等 - expect(temp).not.to.be(normalList[i].a); + expect(temp).not.to.be(normalList1[i].a); // 确保内容一样 - expect(temp).to.eql(normalList[i].a); + expect(temp).to.eql(normalList1[i].a); } }); it('简单循环引用', function() { - var temp = cloneForce(singleRefList[0].a); + var temp = cloneForce(singleRefList1[0].a); expect(temp).to.be(temp[3]); - var temp = cloneForce(singleRefList[1].a); + var temp = cloneForce(singleRefList1[1].a); expect(temp).to.be(temp['a4']); }); it('复杂循环引用', function() { - var temp = cloneForce(complexRefList[0].a); + var temp = cloneForce(complexRefList1[0].a); expect(temp).to.be(temp[1][1]); - var temp = cloneForce(complexRefList[1].a); + var temp = cloneForce(complexRefList1[3].a); + expect(temp.has(temp)).to.be(true); + + var temp = cloneForce(complexRefList1[1].a); expect(temp).to.be(temp.a2.b2); + var temp = cloneForce(complexRefList1[4].a); + var values = temp.values() + var temp1 = values.next().value + values = temp1.values() + var value1 = values.next().value + var value2 = values.next().value + + if (type(value1) == 'object'){ + expect(temp).to.be(value1.b); + expect(temp).to.be(value2); + + }else{ + expect(temp).to.be(value2.b); + expect(temp).to.be(value1); + } }); }); }); From 4cd66940c09cd686e943c8c6aa57a208962b2798 Mon Sep 17 00:00:00 2001 From: wanghaoran5 Date: Thu, 25 Oct 2018 21:56:00 +0800 Subject: [PATCH 2/4] =?UTF-8?q?=E5=AE=8C=E6=88=90map=E7=9A=84clone?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/index.js | 33 +++++++++++++++- test/test.js | 107 ++++++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 119 insertions(+), 21 deletions(-) diff --git a/src/index.js b/src/index.js index 219dfcc..6007051 100644 --- a/src/index.js +++ b/src/index.js @@ -132,6 +132,10 @@ export function cloneLoop(x) { const UNIQUE_KEY = 'com.yanhaijing.jsmini.clone' + (new Date).getTime(); const UNIQUE_SET_KEY = 'com.yanhaijing.jsmini.clone.set' + (new Date).getTime(); +const UNIQUE_MAPKEY_KEY = 'com.yanhaijing.jsmini.clone.mapkey' + (new Date).getTime(); +const UNIQUE_MAPVALUE_KEY = 'com.yanhaijing.jsmini.clone.mapvalue' + (new Date).getTime(); + + // weakmap:处理对象关联引用 function SimpleWeakmap (){ @@ -167,7 +171,17 @@ function getWeakMap(){ } function setValueToParent(parent,key,value){ - key == UNIQUE_SET_KEY ? parent.add(value) : parent[key] = value; + + if(key === UNIQUE_SET_KEY){ + parent.add(value); + }else if(key == UNIQUE_MAPVALUE_KEY){ //控制数据循环的顺序,先添加value,再添加key + parent.set(UNIQUE_MAPKEY_KEY,value); + }else if(key == UNIQUE_MAPKEY_KEY){ + parent.set(value,parent.get(UNIQUE_MAPKEY_KEY)); + parent.delete(UNIQUE_MAPKEY_KEY); + }else{ + parent[key] = value; + } return value; } @@ -218,6 +232,7 @@ const checkMap = runOnce(function(){ map.delete(UNIQUE_KEY); return true; } + map.delete(UNIQUE_KEY); } catch (e) { console.log(e.message); } @@ -292,8 +307,22 @@ export function cloneForce(x) { data: s, }); } - } else if (tt === 'Map' && checkMap()){ + } else if (tt === 'map' && checkMap()){ newValue = setValueToParent(parent,key,new Map()); + for (let m of source){ + // 下一次循环 + //先添加key, 再添加value 和 setValueToParent里保持一致 + loopList.push({ + parent: newValue, + key: UNIQUE_MAPKEY_KEY, + data: m[0], + }); + loopList.push({ + parent: newValue, + key: UNIQUE_MAPVALUE_KEY, + data: m[1], + }); + } } else{ setValueToParent(parent,key,source); continue; diff --git a/test/test.js b/test/test.js index 33cffca..0cf4130 100644 --- a/test/test.js +++ b/test/test.js @@ -100,6 +100,19 @@ describe('单元测试', function() { normalList1.push({ a:set, }) + + let map = new Map() + let obj = {} + map.set(1,1) + map.set(2,'a') + map.set('a',null) + map.set('b',1) + map.set(4,undefined) + map.set({},1) + map.set(obj,obj) + normalList1.push({ + a:map, + }) } catch (error) { } @@ -136,25 +149,40 @@ describe('单元测试', function() { } ]; let set = new Set() + + set.add(set) + let set1 = new Set() - set.add(1) - set.add(set1) - set1.add({ - a: 1, - a1:[set1], - a2:{ - a:[set1] - } - }) - set.add([ - 'abc' - ]) - set.add(null) - set.add(set1) + set1.add(set) - singleRefList.push({ + + singleRefList1.push({ a:set, }) + singleRefList1.push({ + a:set1, + }) + + var map = new Map() + map.set('a',map) + + map.set(map,'a') + + var map1 = new Map() + + map1.set('a',{ + 'a4':map1 + }) + map1.set({ + 'a4':map1 + },'a') + + singleRefList1.push({ + a:map, + }) + singleRefList1.push({ + a:map1, + }) } catch (error) { } @@ -205,6 +233,19 @@ describe('单元测试', function() { complexRefList1.push({ a:set1 }) + + + let map = new Map() + let map1 = new Map() + let map2 = new Map() + map1.set('b',map2) + map1.set('a',map) + map1.set(map,'a') + map.set('a',map1) + map.set(map1,'b') + complexRefList1.push({ + a:map + }) } catch (error) { } @@ -285,9 +326,8 @@ describe('单元测试', function() { expect(cloneForce(simpleList[i].a)).to.be(simpleList[i].a); } - for (var i = 0; i < normalList.length; i++) { + for (var i = 0; i < normalList1.length; i++) { var temp = cloneForce(normalList1[i].a); - // 确保不全等 expect(temp).not.to.be(normalList1[i].a); // 确保内容一样 @@ -301,17 +341,35 @@ describe('单元测试', function() { var temp = cloneForce(singleRefList1[1].a); expect(temp).to.be(temp['a4']); + + //set数据检测 + var temp = cloneForce(singleRefList1[3].a); + expect(temp.has(temp)).to.be(true); + var temp1 = cloneForce(singleRefList1[4].a); + expect(temp1.has(temp1)).not.to.be(true); + + //map数据检测 + var temp = cloneForce(singleRefList1[5].a); + expect(temp.has(temp)).to.be(true); + expect(temp.has(temp.get('a'))).to.be(true); + + var temp = cloneForce(singleRefList1[6].a); + // expect(temp.has(temp)).to.be(true); + expect(temp.get('a')['a4']).to.be(temp); + }); it('复杂循环引用', function() { var temp = cloneForce(complexRefList1[0].a); expect(temp).to.be(temp[1][1]); - var temp = cloneForce(complexRefList1[3].a); - expect(temp.has(temp)).to.be(true); var temp = cloneForce(complexRefList1[1].a); expect(temp).to.be(temp.a2.b2); + + //set数据的检测 + var temp = cloneForce(complexRefList1[3].a); + expect(temp.has(temp)).to.be(true); var temp = cloneForce(complexRefList1[4].a); var values = temp.values() var temp1 = values.next().value @@ -327,6 +385,17 @@ describe('单元测试', function() { expect(temp).to.be(value2.b); expect(temp).to.be(value1); } + + //map数据检测 map1.set(map,{}) + + + var temp = cloneForce(complexRefList1[5].a); + + expect(temp.get('a').get('a')).to.be(temp); + expect(temp.get('a').get('b')).not.to.be(temp); + expect(temp.get(temp.get('a'))).to.be('b') + expect(temp.get('a').get(temp.get('a').get('a'))).to.be('a') + }); }); }); From fac4943395c7ca880ccd34da6c52310add6bbb68 Mon Sep 17 00:00:00 2001 From: wanghaoran5 Date: Fri, 26 Oct 2018 09:37:27 +0800 Subject: [PATCH 3/4] =?UTF-8?q?=E7=AE=80=E5=8C=96set=E5=92=8Cmap=E5=87=BD?= =?UTF-8?q?=E6=95=B0=E5=8A=9F=E8=83=BD=E7=9A=84=E6=A3=80=E6=B5=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/index.js | 31 ++++++------------------------- 1 file changed, 6 insertions(+), 25 deletions(-) diff --git a/src/index.js b/src/index.js index 6007051..dd9376d 100644 --- a/src/index.js +++ b/src/index.js @@ -185,28 +185,9 @@ function setValueToParent(parent,key,value){ return value; } -/** - * - * @param {function} fn 被执行的函数 - * - * 返回一个函数a,该函数a会缓存fn的执行结果 - */ -function runOnce(fn){ - let result; - let time = 0; - return function(){ - if(time > 0){ - return result; - } - time++; - result = fn(); - - return result; - }; -} //检测Set功能 -const checkSet = runOnce(function(){ +const checkSet = (function(){ try { let set = new Set(); set.add(UNIQUE_KEY); @@ -220,9 +201,9 @@ const checkSet = runOnce(function(){ console.log(e.message); } return false; -}); +})(); //检测Map的功能 -const checkMap = runOnce(function(){ +const checkMap = (function(){ try { let map = new Map(); map.set(UNIQUE_KEY,'Map'); @@ -237,7 +218,7 @@ const checkMap = runOnce(function(){ console.log(e.message); } return false; -}); +})(); export function cloneForce(x) { const uniqueData = getWeakMap(); @@ -297,7 +278,7 @@ export function cloneForce(x) { }); } } - } else if (tt === 'set' && checkSet()){ + } else if (tt === 'set' && checkSet){ newValue = setValueToParent(parent,key,new Set()); for (let s of source){ // 下一次循环 @@ -307,7 +288,7 @@ export function cloneForce(x) { data: s, }); } - } else if (tt === 'map' && checkMap()){ + } else if (tt === 'map' && checkMap){ newValue = setValueToParent(parent,key,new Map()); for (let m of source){ // 下一次循环 From e9aa63b0937d292b1ab0090c9904d8b30aa65c68 Mon Sep 17 00:00:00 2001 From: wanghaoran5 Date: Fri, 26 Oct 2018 15:47:36 +0800 Subject: [PATCH 4/4] =?UTF-8?q?=E4=BF=AE=E5=A4=8Dtest.js=E5=9C=A8node=204?= =?UTF-8?q?=E4=B8=8B=E4=B8=8D=E6=94=AF=E6=8C=81=E7=9A=84bug=20=EF=BC=88?= =?UTF-8?q?=E4=B8=8D=E6=94=AF=E6=8C=81let=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/test.js | 98 +++++++++++++++++++++++++++++----------------------- 1 file changed, 54 insertions(+), 44 deletions(-) diff --git a/test/test.js b/test/test.js index 0cf4130..af5a1c9 100644 --- a/test/test.js +++ b/test/test.js @@ -81,8 +81,8 @@ describe('单元测试', function() { a: {a1: 1, a2: [1, {b1: 1, b2: [{c1: 1, c2: 2}]}]} } ]; - let set = new Set() - let set1 = new Set() + var set = new Set() + var set1 = new Set() set.add(1) set.add(set1) set.add({ @@ -101,8 +101,8 @@ describe('单元测试', function() { a:set, }) - let map = new Map() - let obj = {} + var map = new Map() + var obj = {} map.set(1,1) map.set(2,'a') map.set('a',null) @@ -148,11 +148,11 @@ describe('单元测试', function() { a: b, } ]; - let set = new Set() + var set = new Set() set.add(set) - let set1 = new Set() + var set1 = new Set() set1.add(set) @@ -217,9 +217,9 @@ describe('单元测试', function() { a: b, } ]; - let set = new Set() - let set1 = new Set() - let set2 = new Set() + var set = new Set() + var set1 = new Set() + var set2 = new Set() set.add(set) complexRefList1.push({ @@ -235,9 +235,9 @@ describe('单元测试', function() { }) - let map = new Map() - let map1 = new Map() - let map2 = new Map() + var map = new Map() + var map1 = new Map() + var map2 = new Map() map1.set('b',map2) map1.set('a',map) map1.set(map,'a') @@ -343,19 +343,25 @@ describe('单元测试', function() { expect(temp).to.be(temp['a4']); //set数据检测 - var temp = cloneForce(singleRefList1[3].a); - expect(temp.has(temp)).to.be(true); - var temp1 = cloneForce(singleRefList1[4].a); - expect(temp1.has(temp1)).not.to.be(true); + if(singleRefList1[3]){ + var temp = cloneForce(singleRefList1[3].a); + expect(temp.has(temp)).to.be(true); + var temp1 = cloneForce(singleRefList1[4].a); + expect(temp1.has(temp1)).not.to.be(true); + } //map数据检测 - var temp = cloneForce(singleRefList1[5].a); - expect(temp.has(temp)).to.be(true); - expect(temp.has(temp.get('a'))).to.be(true); - var temp = cloneForce(singleRefList1[6].a); - // expect(temp.has(temp)).to.be(true); - expect(temp.get('a')['a4']).to.be(temp); + if(singleRefList1[5]){ + var temp = cloneForce(singleRefList1[5].a); + expect(temp.has(temp)).to.be(true); + expect(temp.has(temp.get('a'))).to.be(true); + + var temp = cloneForce(singleRefList1[6].a); + // expect(temp.has(temp)).to.be(true); + expect(temp.get('a')['a4']).to.be(temp); + } + }); @@ -368,33 +374,37 @@ describe('单元测试', function() { expect(temp).to.be(temp.a2.b2); //set数据的检测 - var temp = cloneForce(complexRefList1[3].a); - expect(temp.has(temp)).to.be(true); - var temp = cloneForce(complexRefList1[4].a); - var values = temp.values() - var temp1 = values.next().value - values = temp1.values() - var value1 = values.next().value - var value2 = values.next().value - - if (type(value1) == 'object'){ - expect(temp).to.be(value1.b); - expect(temp).to.be(value2); + if (complexRefList1[3]){ + var temp = cloneForce(complexRefList1[3].a); + expect(temp.has(temp)).to.be(true); + var temp = cloneForce(complexRefList1[4].a); + var values = temp.values() + var temp1 = values.next().value + values = temp1.values() + var value1 = values.next().value + var value2 = values.next().value - }else{ - expect(temp).to.be(value2.b); - expect(temp).to.be(value1); + if (type(value1) == 'object'){ + expect(temp).to.be(value1.b); + expect(temp).to.be(value2); + + }else{ + expect(temp).to.be(value2.b); + expect(temp).to.be(value1); + } } - //map数据检测 map1.set(map,{}) + //map数据检测 + if(complexRefList1[5]){ + + var temp = cloneForce(complexRefList1[5].a); - var temp = cloneForce(complexRefList1[5].a); - - expect(temp.get('a').get('a')).to.be(temp); - expect(temp.get('a').get('b')).not.to.be(temp); - expect(temp.get(temp.get('a'))).to.be('b') - expect(temp.get('a').get(temp.get('a').get('a'))).to.be('a') + expect(temp.get('a').get('a')).to.be(temp); + expect(temp.get('a').get('b')).not.to.be(temp); + expect(temp.get(temp.get('a'))).to.be('b') + expect(temp.get('a').get(temp.get('a').get('a'))).to.be('a') + } }); });