Skip to content

Commit

Permalink
Merge pull request #5 from jsmini/optimize
Browse files Browse the repository at this point in the history
使用weakMap优化cloneForce,低版本下自定义一个SimpleWeakmap
  • Loading branch information
yanhaijing authored Oct 18, 2018
2 parents d192243 + 9a6ef18 commit 33849dd
Show file tree
Hide file tree
Showing 5 changed files with 399 additions and 35 deletions.
41 changes: 35 additions & 6 deletions demo/cloneForce-version.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@
<script>
var cloneForce011 = jsmini_clone.cloneForce;
</script>
<script src="js/clone-0.2.0.aio.js"></script>
<script>
var cloneForce020 = jsmini_clone.cloneForce;
</script>

<script src="../dist/index.aio.js"></script>
<script src="js/comm.js"></script>
<script>
Expand All @@ -17,14 +22,38 @@
var data2 = createData(1000, 0);
var data3 = createData(10000, 0);

safeRun('100 object cloneForce011', function () { cloneForce011(data1) })
safeRun('100 object cloneForce', function () { cloneForce(data1) })

safeRun('1000 object cloneForce011', function () { cloneForce011(data2) })
safeRun('1000 object cloneForce', function () { cloneForce(data2) })
function run(list) {
if (list.length === 0) return;

console.log('2000ms内运行的次数:', list[0]());

setTimeout(function () {run(list.slice(1))}, 1000);
}

var list1 = [
function () {return runTime(function() {cloneForce011(data1)}, 2000)},
function () {return runTime(function() {cloneForce020(data1)}, 2000)},
function () {return runTime(function() {cloneForce(data1)}, 2000)},
];

run(list1)

var list2 = [
function () {return runTime(function() {cloneForce011(data2)}, 2000)},
function () {return runTime(function() {cloneForce020(data2)}, 2000)},
function () {return runTime(function() {cloneForce(data2)}, 2000)},
];

setTimeout(function () { run(list2) }, 10000)

var list3 = [
function () {return runTime(function() {cloneForce011(data3)}, 2000)},
function () {return runTime(function() {cloneForce020(data3)}, 2000)},
function () {return runTime(function() {cloneForce(data3)}, 2000)},
];

safeRun('10000 object cloneForce011', function () { cloneForce011(data3) })
safeRun('10000 object cloneForce', function () { cloneForce(data3) })
setTimeout(function () { run(list3) }, 20000)
</script>
</body>
</html>
311 changes: 311 additions & 0 deletions demo/js/clone-0.2.0.aio.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,311 @@
/*!
* clone 0.2.0 (https://github.com/jsmini/clone)
* API https://github.com/jsmini/clone/blob/master/doc/api.md
* Copyright 2017-2018 jsmini. All Rights Reserved
* Licensed under MIT (https://github.com/jsmini/clone/blob/master/LICENSE)
*/

(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
(factory((global.jsmini_clone = {})));
}(this, (function (exports) { 'use strict';

/*!
* type 0.4.1 (https://github.com/jsmini/type)
* API https://github.com/jsmini/type/blob/master/doc/api.md
* Copyright 2017-2018 jsmini. All Rights Reserved
* Licensed under MIT (https://github.com/jsmini/type/blob/master/LICENSE)
*/

const toString = Object.prototype.toString;

function type(x) {
if(x === null){
return 'null';
}

const t= typeof x;

if(t !== 'object'){
return t;
}

let c;
try {
c = toString.call(x).slice(8, -1).toLowerCase();
} catch(e) {
return 'object';
}

if(c !== 'object'){
return c;
}

if(x.constructor == Object){
return c;
}

try {
// Object.create(null)
if (Object.getPrototypeOf(x) === null || x.__proto__ === null) {
return 'object';
}

return 'unknown';
} catch(e) {
// ie下无Object.getPrototypeOf
return 'unknown';
}
}

// Object.create(null) 的对象,没有hasOwnProperty方法
function hasOwnProp(obj, key) {
return Object.prototype.hasOwnProperty.call(obj, key);
}

// 仅对对象和数组进行深拷贝,其他类型,直接返回
function isClone(x) {
var t = type(x);
return t === 'object' || t === 'array';
}

// 递归
function clone(x) {
if (!isClone(x)) return x;

var t = type(x);

var res = void 0;

if (t === 'array') {
res = [];
for (var i = 0; i < x.length; i++) {
// 避免一层死循环 a.b = a
res[i] = x[i] === x ? res : clone(x[i]);
}
} else if (t === 'object') {
res = {};
for (var key in x) {
if (hasOwnProp(x, key)) {
// 避免一层死循环 a.b = a
res[key] = x[key] === x ? res : clone(x[key]);
}
}
}

return res;
}

// 通过JSON深拷贝
function cloneJSON(x) {
var errOrDef = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;

if (!isClone(x)) return x;

try {
return JSON.parse(JSON.stringify(x));
} catch (e) {
if (errOrDef === true) {
throw e;
} else {
console.error('cloneJSON error: ' + e.message);
return errOrDef;
}
}
}

// 循环
function cloneLoop(x) {
var t = type(x);

var root = x;

if (t === 'array') {
root = [];
} else if (t === 'object') {
root = {};
}

// 循环数组
var loopList = [{
parent: root,
key: undefined,
data: x
}];

while (loopList.length) {
// 深度优先
var node = loopList.pop();
var parent = node.parent;
var key = node.key;
var data = node.data;
var tt = type(data);

// 初始化赋值目标,key为undefined则拷贝到父元素,否则拷贝到子元素
var res = parent;
if (typeof key !== 'undefined') {
res = parent[key] = tt === 'array' ? [] : {};
}

if (tt === 'array') {
for (var i = 0; i < data.length; i++) {
// 避免一层死循环 a.b = a
if (data[i] === data) {
res[i] = res;
} else if (isClone(data[i])) {
// 下一次循环
loopList.push({
parent: res,
key: i,
data: data[i]
});
} else {
res[i] = data[i];
}
}
} else if (tt === 'object') {
for (var k in data) {
if (hasOwnProp(data, k)) {
// 避免一层死循环 a.b = a
if (data[k] === data) {
res[k] = res;
} else if (isClone(data[k])) {
// 下一次循环
loopList.push({
parent: res,
key: k,
data: data[k]
});
} else {
res[k] = data[k];
}
}
}
}
}

return root;
}

// 保持引用关系
var UNIQUE_KEY = 'com.yanhaijing.' + new Date().getTime();

// 创建数据
function createData() {
return [];
}
// 将数据加入暂存区
function setData(data, source, target) {
var index = data.length;
data[index] = { source: source, target: target };
source[UNIQUE_KEY] = index;
}
// 查找缓存
function findData(data, source) {
var index = source[UNIQUE_KEY];

if (typeof index === 'number') {
return data[index].target;
}

return false;
}
// 清除缓存
function clearData(data) {
for (var i = 0; i < data.length; i++) {
delete data[i].source[UNIQUE_KEY];
}
data.length = 0;
}
function cloneForce(x) {
var uniqueData = createData();
var t = type(x);

var root = x;

if (t === 'array') {
root = [];
} else if (t === 'object') {
root = {};
}

// 循环数组
var loopList = [{
parent: root,
key: undefined,
data: x
}];

while (loopList.length) {
// 深度优先
var node = loopList.pop();
var parent = node.parent;
var key = node.key;
var source = node.data;
var tt = type(source);

// 初始化赋值目标,key为undefined则拷贝到父元素,否则拷贝到子元素
var target = parent;
if (typeof key !== 'undefined') {
target = parent[key] = tt === 'array' ? [] : {};
}

// 复杂数据需要缓存操作
if (isClone(source)) {
// 命中缓存,直接返回缓存数据
var uniqueTarget = findData(uniqueData, source);
if (uniqueTarget) {
parent[key] = uniqueTarget;
continue; // 中断本次循环
}

// 未命中缓存,保存到缓存
setData(uniqueData, source, target);
}

if (tt === 'array') {
for (var 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 (var 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];
}
}
}
}
}

clearData(uniqueData);

return root;
}

exports.clone = clone;
exports.cloneJSON = cloneJSON;
exports.cloneLoop = cloneLoop;
exports.cloneForce = cloneForce;

Object.defineProperty(exports, '__esModule', { value: true });

})));
7 changes: 6 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
"rollup-plugin-node-resolve": "3.0.3"
},
"dependencies": {
"@jsmini/guid": "0.7.0",
"@jsmini/type": "0.4.1",
"babel-runtime": "6.26.0"
}
Expand Down
Loading

0 comments on commit 33849dd

Please sign in to comment.