├── .editorconfig ├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── index.d.ts ├── index.js ├── package.json └── test └── index.js /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | npm-debug.log 2 | coverage/ 3 | node_modules/ 4 | package-lock.json 5 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | 2 | language: node_js 3 | 4 | node_js: 5 | - node 6 | - 6 7 | - 4 8 | 9 | after_script: 10 | - npm run test-cov 11 | - cat ./coverage/lcov.info | coveralls 12 | 13 | sudo: false 14 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) Simeon Velichkov 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # deep-copy 3 | 4 | [![npm-version]][npm] [![travis-ci]][travis] [![coveralls-status]][coveralls] 5 | 6 | 7 | ```js 8 | var dcopy = require('deep-copy') 9 | 10 | // deep copy object 11 | var copy = dcopy({a: {b: [{c: 5}]}}) 12 | 13 | // deep copy array 14 | var copy = dcopy([1, 2, {a: {b: 5}}]) 15 | ``` 16 | 17 | ### [Benchmarks][benchmarks] 18 | 19 | Benchmarks comparing `deep-copy` to other libraries across all Node LTS versions. 20 | 21 | [npm-version]: https://img.shields.io/npm/v/deep-copy.svg?style=flat-square (NPM Version) 22 | [travis-ci]: https://img.shields.io/travis/simov/deep-copy/master.svg?style=flat-square (Build Status) 23 | [coveralls-status]: https://img.shields.io/coveralls/simov/deep-copy.svg?style=flat-square (Test Coverage) 24 | 25 | [npm]: https://www.npmjs.com/package/deep-copy 26 | [travis]: https://travis-ci.org/simov/deep-copy 27 | [coveralls]: https://coveralls.io/r/simov/deep-copy?branch=master 28 | [benchmarks]: https://github.com/ahmadnassri/benchmark-node-clone 29 | -------------------------------------------------------------------------------- /index.d.ts: -------------------------------------------------------------------------------- 1 | declare function dcopy(arg: T): T 2 | 3 | export default dcopy -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 2 | ;(function (name, root, factory) { 3 | if (typeof exports === 'object') { 4 | module.exports = factory() 5 | } 6 | /* istanbul ignore next */ 7 | else if (typeof define === 'function' && define.amd) { 8 | define(factory) 9 | } 10 | else { 11 | root[name] = factory() 12 | } 13 | }('dcopy', this, function () { 14 | /** 15 | * Deep copy objects and arrays 16 | * 17 | * @param {Object/Array} target 18 | * @return {Object/Array} copy 19 | * @api public 20 | */ 21 | 22 | return function (target) { 23 | if (/number|string|boolean/.test(typeof target)) { 24 | return target 25 | } 26 | if (target instanceof Date) { 27 | return new Date(target.getTime()) 28 | } 29 | 30 | var copy = (target instanceof Array) ? [] : {} 31 | walk(target, copy) 32 | return copy 33 | 34 | function walk (target, copy) { 35 | for (var key in target) { 36 | var obj = target[key] 37 | if (obj instanceof Date) { 38 | var value = new Date(obj.getTime()) 39 | add(copy, key, value) 40 | } 41 | else if (obj instanceof Function) { 42 | var value = obj 43 | add(copy, key, value) 44 | } 45 | else if (obj instanceof Array) { 46 | var value = [] 47 | var last = add(copy, key, value) 48 | walk(obj, last) 49 | } 50 | else if (obj instanceof Object) { 51 | var value = {} 52 | var last = add(copy, key, value) 53 | walk(obj, last) 54 | } 55 | else { 56 | var value = obj 57 | add(copy, key, value) 58 | } 59 | } 60 | } 61 | } 62 | 63 | /** 64 | * Adds a value to the copy object based on its type 65 | * 66 | * @api private 67 | */ 68 | 69 | function add (copy, key, value) { 70 | if (copy instanceof Array) { 71 | copy.push(value) 72 | return copy[copy.length - 1] 73 | } 74 | else if (copy instanceof Object) { 75 | copy[key] = value 76 | return copy[key] 77 | } 78 | } 79 | })) 80 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "deep-copy", 3 | "version": "1.4.2", 4 | "description": "Deep copy objects and arrays", 5 | "keywords": [ 6 | "deep", 7 | "copy", 8 | "object", 9 | "array" 10 | ], 11 | "license": "MIT", 12 | "homepage": "https://github.com/simov/deep-copy", 13 | "author": "Simeon Velichkov (https://simov.github.io)", 14 | "repository": { 15 | "type": "git", 16 | "url": "https://github.com/simov/deep-copy.git" 17 | }, 18 | "dependencies": {}, 19 | "devDependencies": { 20 | "coveralls": "^2.11.15", 21 | "istanbul": "^0.4.5", 22 | "mocha": "^3.2.0" 23 | }, 24 | "main": "index.js", 25 | "typings": "index.d.ts", 26 | "files": [ 27 | "LICENSE", 28 | "README.md", 29 | "index.d.ts", 30 | "index.js" 31 | ], 32 | "scripts": { 33 | "test": "npm run test-ci", 34 | "test-ci": "mocha test/", 35 | "test-cov": "istanbul cover _mocha test/" 36 | }, 37 | "engines": { 38 | "node": ">=4.0.0" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /test/index.js: -------------------------------------------------------------------------------- 1 | 2 | var t = require('assert') 3 | var dcopy = require('../') 4 | 5 | 6 | describe('preserve', function () { 7 | it('number', function () { 8 | var copy = dcopy(42) 9 | t.deepStrictEqual(copy, 42) 10 | }) 11 | 12 | it('string', function () { 13 | var copy = dcopy('a') 14 | t.deepStrictEqual(copy, 'a') 15 | }) 16 | 17 | it('boolean', function () { 18 | var copy = dcopy(true) 19 | t.deepStrictEqual(copy, true) 20 | }) 21 | }) 22 | 23 | describe('copy', function () { 24 | it('object', function () { 25 | var target = {a: 0} 26 | var copy = dcopy(target) 27 | t.deepStrictEqual(target, copy) 28 | 29 | copy.a = 1 30 | t.notDeepStrictEqual(target, copy) 31 | 32 | t.deepStrictEqual(target, {a: 0}) 33 | t.deepStrictEqual(copy, {a: 1}) 34 | }) 35 | 36 | it('array', function () { 37 | var target = [0] 38 | var copy = dcopy(target) 39 | t.deepStrictEqual(target, copy) 40 | 41 | copy[0] = 1 42 | t.notDeepStrictEqual(target, copy) 43 | 44 | t.deepStrictEqual(target, [0]) 45 | t.deepStrictEqual(copy, [1]) 46 | }) 47 | 48 | it('date', function () { 49 | var target = new Date(2017, 0, 1) 50 | var copy = dcopy(target) 51 | t.deepStrictEqual(target, copy) 52 | 53 | copy.setMonth(5) 54 | t.notDeepStrictEqual(target, copy) 55 | 56 | t.deepStrictEqual(target.getMonth(), 0) 57 | t.deepStrictEqual(copy.getMonth(), 5) 58 | }) 59 | }) 60 | 61 | 62 | describe('deep copy', function () { 63 | it('object', function () { 64 | var target = { 65 | object: {a: 0} 66 | } 67 | var copy = dcopy(target) 68 | t.deepStrictEqual(target, copy) 69 | 70 | copy.object.a = 1 71 | t.notDeepStrictEqual(target, copy) 72 | 73 | t.deepStrictEqual(target, {object: {a: 0}}) 74 | t.deepStrictEqual(copy, {object: {a: 1}}) 75 | }) 76 | 77 | it('array', function () { 78 | var target = { 79 | array: [0] 80 | } 81 | var copy = dcopy(target) 82 | t.deepStrictEqual(target, copy) 83 | 84 | copy.array[0] = 1 85 | t.notDeepStrictEqual(target, copy) 86 | 87 | t.deepStrictEqual(target, {array: [0]}) 88 | t.deepStrictEqual(copy, {array: [1]}) 89 | }) 90 | 91 | it('date', function () { 92 | var target = { 93 | date: new Date(2017, 0, 1) 94 | } 95 | var copy = dcopy(target) 96 | t.deepStrictEqual(target, copy) 97 | 98 | copy.date.setMonth(5) 99 | t.notDeepStrictEqual(target, copy) 100 | 101 | t.deepStrictEqual(target.date.getMonth(), 0) 102 | t.deepStrictEqual(copy.date.getMonth(), 5) 103 | }) 104 | }) 105 | 106 | describe('deep preserve', function () { 107 | it('function', function () { 108 | var target = { 109 | func: function () {} 110 | } 111 | var copy = dcopy(target) 112 | t.deepStrictEqual(target, copy) 113 | 114 | t.deepStrictEqual(typeof copy.func, 'function') 115 | }) 116 | }) 117 | --------------------------------------------------------------------------------