├── .gitignore ├── test └── index-test.js ├── package.json ├── LICENSE ├── README.md └── index.js /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | 5 | # Runtime data 6 | pids 7 | *.pid 8 | *.seed 9 | 10 | # Directory for instrumented libs generated by jscoverage/JSCover 11 | lib-cov 12 | 13 | # Coverage directory used by tools like istanbul 14 | coverage 15 | 16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 17 | .grunt 18 | 19 | # node-waf configuration 20 | .lock-wscript 21 | 22 | # Compiled binary addons (http://nodejs.org/api/addons.html) 23 | build/Release 24 | 25 | # Dependency directory 26 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git 27 | node_modules 28 | 29 | .idea 30 | -------------------------------------------------------------------------------- /test/index-test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const assert = require('assert'); 4 | const FastClone = require('../'); 5 | 6 | describe('index', function () { 7 | it('FastClone.factory', function () { 8 | const sourceArray = [ 9 | {a: 1, b: [{c: "d", f: {g: 3}}]}, 10 | {a: 2, b: [{c: "e", f: {g: 4}}]} 11 | ]; 12 | const clonedArray = FastClone.cloneArray(sourceArray); 13 | 14 | assert.deepEqual(sourceArray[0], clonedArray[0]); 15 | assert.deepEqual(sourceArray[1], clonedArray[1]); 16 | 17 | clonedArray[0].a = 3; 18 | clonedArray[0].b[0].c = "f"; 19 | clonedArray[0].b[0].f.g = 10; 20 | 21 | assert.notDeepEqual(sourceArray[0], clonedArray[0]); 22 | assert.notEqual(sourceArray[0].b[0].f.g, clonedArray[0].b[0].f.g); 23 | }); 24 | }); -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "fastest-clone", 3 | "version": "1.0.1", 4 | "description": "Library for fastest array cloning or copy objects with similar structures", 5 | "main": "index.js", 6 | "directories": { 7 | "test": "test" 8 | }, 9 | "dependencies": {}, 10 | "devDependencies": { 11 | "mocha": "^2.5.3" 12 | }, 13 | "scripts": { 14 | "test": "mocha" 15 | }, 16 | "repository": { 17 | "type": "git", 18 | "url": "git+https://github.com/ivolovikov/fastest-clone.git" 19 | }, 20 | "keywords": [ 21 | "clone", 22 | "fast clone", 23 | "fast array clone", 24 | "fast array object" 25 | ], 26 | "author": "Ivan Volovikov", 27 | "license": "MIT", 28 | "bugs": { 29 | "url": "https://github.com/ivolovikov/fastest-clone/issues" 30 | }, 31 | "homepage": "https://github.com/ivolovikov/fastest-clone#readme" 32 | } 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Ivan Volovikov 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Fast Array Clone Library 2 | 3 | This library can **200X times faster** than *lodash* (benchmark) make deep copies of an array or objects with similar structure in JavaScript 4 | 5 | ### EXAMPLE 6 | ```javascript 7 | // array of SAME STRUCTURED object 8 | var sourceArray = [{ f1 : ..., f2: ... }, ...]; 9 | ``` 10 | 11 | You can use built-in array clone function: 12 | ```javascript 13 | var clonedArray = FastClone.cloneArray(sourceArray); 14 | ``` 15 | or object clone constructor factory: 16 | ```javascript 17 | // creating deep clone constructor function 18 | var Clone = FastClone.factory(sourceArray[0]); 19 | var clonedArray = sourceArray.map(function(item) { 20 | // you can add here custom logic 21 | return new Clone(item); 22 | }); 23 | ``` 24 | ### INSTALLATION 25 | In a browser: 26 | ```html 27 | 28 | ``` 29 | Using npm: 30 | ``` 31 | npm install fastest-clone 32 | ``` 33 | ### BENCHMARK 34 | Result for Chromium 50.0.2661.102 Ubuntu 14.04 (64-bit) 35 | 36 | Library | Ops/sec 37 | ------------ | ------------- 38 | lodash | 66,313 39 | JQuery | 62,164 40 | **FastClone** | **16,927,673** 41 | Benchmark source code - benchmark 42 | 43 | 44 | ### LICENSE 45 | 46 | Copyright (c) 2016 Ivan Volovikov 47 | 48 | Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php 49 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * FastClone JavaScript Library v1.0.0 3 | * 4 | * This library perform very fast cloning 5 | * of objects WITH THE SAME STRUCTURE 6 | * 7 | * @example 8 | * var sourceArray = [{ f1 : ..., f2: ... }, ...]; // array of SAME STRUCTURED object 9 | * 10 | * // you can use built-in function for clone array 11 | * var clonedArray = FastClone.cloneArray(sourceArray); 12 | * 13 | * // or write a custom code with clone constructor factory 14 | * var Clone = FastClone.factory(sourceArray[0]); // creating deep clone constructor function 15 | * var clonedArray = sourceArray.map(function(item) { 16 | * return new Clone(item); 17 | * }); 18 | * 19 | * Copyright 2015 Ivan Volovikov 20 | * Released under the MIT license 21 | * https://github.com/ivolovikov/fastest-clone 22 | */ 23 | var FastClone = { 24 | 25 | /** 26 | * This is a factory method that creates clone constructor function 27 | * for a specified object 28 | * 29 | * @param {Object} source - source object that need to be cloned next 30 | * @param {Boolean} isDeep - flag that represents should be clone deep or not (default: true) 31 | * @returns {Function} 32 | */ 33 | factory: function (source, isDeep) { 34 | if (typeof source != 'object' || Array.isArray(source)) { 35 | throw new Error('Source is not an object'); 36 | } 37 | var deep = isDeep === undefined ? true : isDeep; 38 | 39 | return new Function('src', FastClone._getKeyMap(source, deep)); 40 | }, 41 | 42 | /** 43 | * This method is for array cloning 44 | * 45 | * @param {Array} source - source array to clone 46 | * @param {Boolean} isDeep - flag that represents should be clone deep or not (default: true) 47 | * @returns {Array} 48 | */ 49 | cloneArray: function(source, isDeep) { 50 | if (!Array.isArray(source)) { 51 | throw new Error('Source should be an array'); 52 | } 53 | var deep = isDeep === undefined ? true : isDeep; 54 | 55 | var clonedArray = []; 56 | if (source.length) { 57 | var Clone = FastClone.factory(source[0], deep); 58 | for (var i = 0; i < source.length; i++) { 59 | clonedArray.push(new Clone(source[i])); 60 | } 61 | } 62 | return clonedArray; 63 | }, 64 | 65 | /** 66 | * This method create map of object fields 67 | * for eval in clone function 68 | * 69 | * @param {Object|Array} source - source object that need to be cloned next 70 | * @param {Boolean} deep - flag that represents should be clone deep or not 71 | * @param {String} baseKey - current sequence of object keys 72 | * @param {Number} arrIndex - current sequence of array indexes 73 | * @returns {string} 74 | */ 75 | _getKeyMap: function (source, deep, baseKey, arrIndex) { 76 | var base = baseKey || ''; 77 | var index = (arrIndex || 0) + 1; 78 | 79 | var keysMap = base ? 'this' + base : ''; 80 | 81 | if (Array.isArray(source)) { 82 | var iterVal = 'i' + index; // name of the current counter value 83 | var iterPath = base + '[' + iterVal + ']'; // path of the current array value 84 | 85 | if (typeof source[0] == 'object') { 86 | // This cycle will write code for copy array values 87 | keysMap += base ? ' = [];' : ''; 88 | keysMap += 'for (var ' + iterVal + ' = 0; ' + iterVal + ' < src' + base + '.length; ' + iterVal + '++) {'; 89 | keysMap += FastClone._getKeyMap(source[0], deep, iterPath, index); 90 | keysMap += '}'; 91 | } else { 92 | keysMap += ' = src' + base + '.slice();'; 93 | } 94 | } else { 95 | keysMap += base ? ' = {};' : ''; 96 | 97 | // Iterate over object keys 98 | for (var key in source) { 99 | if (!source.hasOwnProperty(key)) { 100 | continue; 101 | } 102 | 103 | var value = source[key]; 104 | var path = base + '.' + key; // current key path 105 | 106 | if (deep && typeof value == 'object' && value !== null) { 107 | keysMap += FastClone._getKeyMap(value, deep, path, index); 108 | } else { 109 | keysMap += 'this' + path + ' = src' + path + ';'; 110 | } 111 | } 112 | } 113 | 114 | return keysMap; 115 | } 116 | }; 117 | 118 | if (typeof module == 'object' && typeof module.exports == 'object') { 119 | module.exports = FastClone; 120 | } 121 | --------------------------------------------------------------------------------