├── .gitignore ├── Makefile ├── component.json ├── Readme.md ├── package.json ├── History.md ├── index.js └── test └── clone.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | REPORTER = dot 3 | 4 | test: 5 | @./node_modules/.bin/mocha \ 6 | --reporter $(REPORTER) \ 7 | --bail 8 | 9 | .PHONY: test 10 | -------------------------------------------------------------------------------- /component.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "clone", 3 | "repo": "component/clone", 4 | "version": "0.2.3", 5 | "dependencies": { 6 | "component/type": "*" 7 | }, 8 | "devDependencies": { 9 | "visionmedia/mocha": "*", 10 | "guille/expect.js": "*" 11 | }, 12 | "scripts": [ 13 | "index.js" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | 2 | # clone 3 | 4 | Object clone supporting `date`, `regexp`, `array` and `object` types. 5 | 6 | ## Example 7 | 8 | ```js 9 | var obj = clone({ 10 | a: 'b', 11 | c: [ 12 | new Date(), 13 | 'tobi', 14 | 'jane' 15 | ] 16 | }) 17 | ``` 18 | 19 | ## API 20 | 21 | ### clone(obj) 22 | 23 | Clones `obj` recursively and returns it. 24 | 25 | ## License 26 | 27 | MIT 28 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "component-clone", 3 | "version": "0.2.3", 4 | "dependencies": { 5 | "component-type": "*" 6 | }, 7 | "devDependencies": { 8 | "mocha": "*", 9 | "expect.js": "*" 10 | }, 11 | "component": { 12 | "scripts": { 13 | "clone/index.js": "index.js" 14 | } 15 | }, 16 | "scripts": { 17 | "test": "make test" 18 | }, 19 | "repository": { 20 | "type": "git", 21 | "url": "https://github.com/component/clone.git" 22 | }, 23 | "browser": { 24 | "type": "component-type" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /History.md: -------------------------------------------------------------------------------- 1 | 2 | 0.2.3 / 2016-07-21 3 | ================== 4 | 5 | * use safer Object.prototype.hasOwnProperty 6 | 7 | 0.2.2 / 2014-03-06 8 | ================== 9 | 10 | * fix require() call again 11 | 12 | 0.2.1 / 2014-03-01 13 | ================== 14 | 15 | * make clone work in all environments FOR REAL 16 | * change npm name to component-clone 17 | 18 | 0.2.0 / 2014-01-27 19 | ================== 20 | 21 | * make clone work in all environments 22 | 23 | 0.1.1 / 2014-01-07 24 | ================== 25 | 26 | * add repo field to component.json 27 | * add tests around cloning functions 28 | * package: fixed package.json 29 | 30 | 0.1.0 / 2012-10-18 31 | ================== 32 | 33 | * initial release 34 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Module dependencies. 3 | */ 4 | 5 | var type; 6 | try { 7 | type = require('component-type'); 8 | } catch (_) { 9 | type = require('type'); 10 | } 11 | 12 | /** 13 | * Module exports. 14 | */ 15 | 16 | module.exports = clone; 17 | 18 | /** 19 | * Clones objects. 20 | * 21 | * @param {Mixed} any object 22 | * @api public 23 | */ 24 | 25 | function clone(obj){ 26 | switch (type(obj)) { 27 | case 'object': 28 | var copy = {}; 29 | for (var key in obj) { 30 | if (Object.prototype.hasOwnProperty.call(obj, key)) { 31 | copy[key] = clone(obj[key]); 32 | } 33 | } 34 | return copy; 35 | 36 | case 'array': 37 | var copy = new Array(obj.length); 38 | for (var i = 0, l = obj.length; i < l; i++) { 39 | copy[i] = clone(obj[i]); 40 | } 41 | return copy; 42 | 43 | case 'regexp': 44 | // from millermedeiros/amd-utils - MIT 45 | var flags = ''; 46 | flags += obj.multiline ? 'm' : ''; 47 | flags += obj.global ? 'g' : ''; 48 | flags += obj.ignoreCase ? 'i' : ''; 49 | return new RegExp(obj.source, flags); 50 | 51 | case 'date': 52 | return new Date(obj.getTime()); 53 | 54 | default: // string, number, boolean, … 55 | return obj; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /test/clone.js: -------------------------------------------------------------------------------- 1 | 2 | /* test dependencies */ 3 | 4 | var clone = require('..'); 5 | var expect = require('expect.js'); 6 | 7 | /* tests */ 8 | 9 | describe('clone', function(){ 10 | 11 | it('date', function(){ 12 | var obj = new Date; 13 | var cloned = clone(obj); 14 | expect(cloned.getTime()).to.be(obj.getTime()); 15 | expect(cloned).not.to.be(obj); 16 | }); 17 | 18 | it('regexp', function(){ 19 | var obj = /hello/i; 20 | var cloned = clone(obj); 21 | expect(cloned.toString()).to.be(obj.toString()); 22 | expect(cloned).not.to.be(obj); 23 | }); 24 | 25 | it('array', function(){ 26 | var obj = [1, 2, 3, '4']; 27 | var cloned = clone(obj); 28 | expect(cloned).to.eql(obj); 29 | expect(cloned).not.to.be(obj); 30 | }); 31 | 32 | it('object', function(){ 33 | var obj = { 34 | a: 1, 35 | b: 2, 36 | c: 3 37 | }; 38 | var cloned = clone(obj); 39 | expect(cloned).to.eql(obj); 40 | expect(cloned).not.to.be(obj); 41 | }); 42 | 43 | it('object combined', function(){ 44 | var date = new Date; 45 | var obj = { 46 | a: { 47 | b: [1, 2, date, { hello: 'world' }] 48 | } 49 | }; 50 | var cloned = clone(obj); 51 | expect(cloned).to.eql(obj); 52 | expect(cloned.a).not.to.be(obj.a); 53 | expect(cloned.a.b).not.to.be(obj.a.b); 54 | expect(cloned.a.b[2]).not.to.be(obj.a.b[2]); 55 | expect(cloned.a.b[2].getTime()).to.be(obj.a.b[2].getTime()); 56 | expect(cloned.a.b[3]).to.eql(obj.a.b[3]); 57 | expect(cloned.a.b[3]).not.to.be(obj.a.b[3]); 58 | }); 59 | 60 | it('object with functions', function() { 61 | var func = function () { return 'original'; }; 62 | var host = { fluent: func }; 63 | var cloned = clone(host); 64 | 65 | // cloned function matches original 66 | 67 | expect(cloned.fluent).to.be(func); 68 | 69 | // change cloned function (no longer matches original) 70 | 71 | cloned.fluent = function () { return 'updated'; }; 72 | expect(cloned.fluent).not.to.be(func); 73 | expect(cloned.fluent()).to.be('updated'); 74 | 75 | // original function is still in place 76 | 77 | expect(func()).to.be('original'); 78 | }); 79 | 80 | }); 81 | --------------------------------------------------------------------------------