From 00c66c07b331063a8edde66b046a5fde12a47cdc Mon Sep 17 00:00:00 2001 From: Haoliang Gao Date: Mon, 6 Mar 2017 23:31:50 +0800 Subject: [PATCH] feat: override array as primitive when deep merge (#1) --- .eslintrc | 14 +- .jscs.json | 175 --------- .npmignore | 1 - .travis.yml | 104 +---- README.md | 88 ++--- appveyor.yml | 16 + index.js | 118 +++--- package.json | 83 ++-- test/.eslintrc | 5 - test/index.js | 1008 ++++++++++++++++++++++++------------------------ 10 files changed, 653 insertions(+), 959 deletions(-) delete mode 100644 .jscs.json delete mode 100644 .npmignore create mode 100644 appveyor.yml delete mode 100644 test/.eslintrc diff --git a/.eslintrc b/.eslintrc index 25241e2..dcc6763 100644 --- a/.eslintrc +++ b/.eslintrc @@ -1,15 +1,3 @@ { - "root": true, - - "extends": "@ljharb", - - "rules": { - "complexity": [2, 15], - "eqeqeq": [2, "allow-null"], - "max-depth": [1, 4], - "max-statements": [2, 25], - "no-extra-parens": [1], - "no-magic-numbers": [0], - "no-restricted-syntax": [2, "BreakStatement", "ContinueStatement", "DebuggerStatement", "LabeledStatement", "WithStatement"] - } + "extend": "egg" } diff --git a/.jscs.json b/.jscs.json deleted file mode 100644 index 0284c86..0000000 --- a/.jscs.json +++ /dev/null @@ -1,175 +0,0 @@ -{ - "es3": true, - - "additionalRules": [], - - "requireSemicolons": true, - - "disallowMultipleSpaces": true, - - "disallowIdentifierNames": [], - - "requireCurlyBraces": { - "allExcept": [], - "keywords": ["if", "else", "for", "while", "do", "try", "catch"] - }, - - "requireSpaceAfterKeywords": ["if", "else", "for", "while", "do", "switch", "return", "try", "catch", "function"], - - "disallowSpaceAfterKeywords": [], - - "disallowSpaceBeforeComma": true, - "disallowSpaceAfterComma": false, - "disallowSpaceBeforeSemicolon": true, - - "disallowNodeTypes": [ - "DebuggerStatement", - "LabeledStatement", - "SwitchCase", - "SwitchStatement", - "WithStatement" - ], - - "requireObjectKeysOnNewLine": { "allExcept": ["sameLine"] }, - - "requireSpacesInAnonymousFunctionExpression": { "beforeOpeningRoundBrace": true, "beforeOpeningCurlyBrace": true }, - "requireSpacesInNamedFunctionExpression": { "beforeOpeningCurlyBrace": true }, - "disallowSpacesInNamedFunctionExpression": { "beforeOpeningRoundBrace": true }, - "requireSpacesInFunctionDeclaration": { "beforeOpeningCurlyBrace": true }, - "disallowSpacesInFunctionDeclaration": { "beforeOpeningRoundBrace": true }, - - "requireSpaceBetweenArguments": true, - - "disallowSpacesInsideParentheses": true, - - "disallowSpacesInsideArrayBrackets": true, - - "disallowQuotedKeysInObjects": { "allExcept": ["reserved"] }, - - "disallowSpaceAfterObjectKeys": true, - - "requireCommaBeforeLineBreak": true, - - "disallowSpaceAfterPrefixUnaryOperators": ["++", "--", "+", "-", "~", "!"], - "requireSpaceAfterPrefixUnaryOperators": [], - - "disallowSpaceBeforePostfixUnaryOperators": ["++", "--"], - "requireSpaceBeforePostfixUnaryOperators": [], - - "disallowSpaceBeforeBinaryOperators": [], - "requireSpaceBeforeBinaryOperators": ["+", "-", "/", "*", "=", "==", "===", "!=", "!=="], - - "requireSpaceAfterBinaryOperators": ["+", "-", "/", "*", "=", "==", "===", "!=", "!=="], - "disallowSpaceAfterBinaryOperators": [], - - "disallowImplicitTypeConversion": ["binary", "string"], - - "disallowKeywords": ["with", "eval"], - - "requireKeywordsOnNewLine": [], - "disallowKeywordsOnNewLine": ["else"], - - "requireLineFeedAtFileEnd": true, - - "disallowTrailingWhitespace": true, - - "disallowTrailingComma": true, - - "excludeFiles": ["node_modules/**", "vendor/**"], - - "disallowMultipleLineStrings": true, - - "requireDotNotation": { "allExcept": ["keywords"] }, - - "requireParenthesesAroundIIFE": true, - - "validateLineBreaks": "LF", - - "validateQuoteMarks": { - "escape": true, - "mark": "'" - }, - - "disallowOperatorBeforeLineBreak": [], - - "requireSpaceBeforeKeywords": [ - "do", - "for", - "if", - "else", - "switch", - "case", - "try", - "catch", - "finally", - "while", - "with", - "return" - ], - - "validateAlignedFunctionParameters": { - "lineBreakAfterOpeningBraces": true, - "lineBreakBeforeClosingBraces": true - }, - - "requirePaddingNewLinesBeforeExport": true, - - "validateNewlineAfterArrayElements": { - "maximum": 6 - }, - - "requirePaddingNewLinesAfterUseStrict": true, - - "disallowArrowFunctions": true, - - "disallowMultiLineTernary": true, - - "validateOrderInObjectKeys": false, - - "disallowIdenticalDestructuringNames": true, - - "disallowNestedTernaries": { "maxLevel": 1 }, - - "requireSpaceAfterComma": { "allExcept": ["trailing"] }, - "requireAlignedMultilineParams": false, - - "requireSpacesInGenerator": { - "afterStar": true - }, - - "disallowSpacesInGenerator": { - "beforeStar": true - }, - - "disallowVar": false, - - "requireArrayDestructuring": false, - - "requireEnhancedObjectLiterals": false, - - "requireObjectDestructuring": false, - - "requireEarlyReturn": false, - - "requireCapitalizedConstructorsNew": { - "allExcept": ["Function", "String", "Object", "Symbol", "Number", "Date", "RegExp", "Error", "Boolean", "Array"] - }, - - "requireImportAlphabetized": false, - - "requireSpaceBeforeObjectValues": true, - "requireSpaceBeforeDestructuredValues": true, - - "disallowSpacesInsideTemplateStringPlaceholders": true, - - "disallowArrayDestructuringReturn": false, - - "requireNewlineBeforeSingleStatementsInIf": false, - - "disallowUnusedVariables": true, - - "requireSpacesInsideImportedObjectBraces": true, - - "requireUseStrict": true -} - diff --git a/.npmignore b/.npmignore deleted file mode 100644 index 30d74d2..0000000 --- a/.npmignore +++ /dev/null @@ -1 +0,0 @@ -test \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index 0f02b9b..5ec1467 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,98 +1,12 @@ +sudo: false language: node_js node_js: - - "6.3" - - "6.2" - - "6.1" - - "6.0" - - "5.12" - - "5.11" - - "5.10" - - "5.9" - - "5.8" - - "5.7" - - "5.6" - - "5.5" - - "5.4" - - "5.3" - - "5.2" - - "5.1" - - "5.0" - - "4.4" - - "4.3" - - "4.2" - - "4.1" - - "4.0" - - "iojs-v3.3" - - "iojs-v3.2" - - "iojs-v3.1" - - "iojs-v3.0" - - "iojs-v2.5" - - "iojs-v2.4" - - "iojs-v2.3" - - "iojs-v2.2" - - "iojs-v2.1" - - "iojs-v2.0" - - "iojs-v1.8" - - "iojs-v1.7" - - "iojs-v1.6" - - "iojs-v1.5" - - "iojs-v1.4" - - "iojs-v1.3" - - "iojs-v1.2" - - "iojs-v1.1" - - "iojs-v1.0" - - "0.12" - - "0.11" - - "0.10" - - "0.9" - - "0.8" - - "0.6" - - "0.4" -before_install: - - 'if [ "${TRAVIS_NODE_VERSION}" != "0.9" ]; then case "$(npm --version)" in 1.*) npm install -g npm@1.4.28 ;; 2.*) npm install -g npm@2 ;; esac ; fi' - - 'if [ "${TRAVIS_NODE_VERSION}" != "0.6" ] && [ "${TRAVIS_NODE_VERSION}" != "0.9" ]; then npm install -g npm; fi' + - '4' + - '6' + - '7' +install: + - npm i npminstall && npminstall script: - - 'if [ "${TRAVIS_NODE_VERSION}" != "4.4" ]; then npm run tests-only ; else npm test ; fi' -sudo: false -matrix: - fast_finish: true - allow_failures: - - node_js: "6.2" - - node_js: "6.1" - - node_js: "6.0" - - node_js: "5.11" - - node_js: "5.10" - - node_js: "5.9" - - node_js: "5.8" - - node_js: "5.7" - - node_js: "5.6" - - node_js: "5.5" - - node_js: "5.4" - - node_js: "5.3" - - node_js: "5.2" - - node_js: "5.1" - - node_js: "5.0" - - node_js: "4.3" - - node_js: "4.2" - - node_js: "4.1" - - node_js: "4.0" - - node_js: "iojs-v3.2" - - node_js: "iojs-v3.1" - - node_js: "iojs-v3.0" - - node_js: "iojs-v2.4" - - node_js: "iojs-v2.3" - - node_js: "iojs-v2.2" - - node_js: "iojs-v2.1" - - node_js: "iojs-v2.0" - - node_js: "iojs-v1.7" - - node_js: "iojs-v1.6" - - node_js: "iojs-v1.5" - - node_js: "iojs-v1.4" - - node_js: "iojs-v1.3" - - node_js: "iojs-v1.2" - - node_js: "iojs-v1.1" - - node_js: "iojs-v1.0" - - node_js: "0.11" - - node_js: "0.9" - - node_js: "0.6" - - node_js: "0.4" + - npm run ci +after_script: + - npminstall codecov && codecov diff --git a/README.md b/README.md index 5b8249a..36fd9d0 100644 --- a/README.md +++ b/README.md @@ -1,61 +1,36 @@ -[![Build Status][travis-svg]][travis-url] -[![dependency status][deps-svg]][deps-url] -[![dev dependency status][dev-deps-svg]][dev-deps-url] - -# extend() for Node.js [![Version Badge][npm-version-png]][npm-url] - -`node-extend` is a port of the classic extend() method from jQuery. It behaves as you expect. It is simple, tried and true. - -Notes: - -* Since Node.js >= 4, - [`Object.assign`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign) - now offers the same functionality natively (but without the "deep copy" option). - See [ECMAScript 2015 (ES6) in Node.js](https://nodejs.org/en/docs/es6). -* Some native implementations of `Object.assign` in both Node.js and many - browsers (since NPM modules are for the browser too) may not be fully - spec-compliant. - Check [`object.assign`](https://www.npmjs.com/package/object.assign) module for - a compliant candidate. - -## Installation - -This package is available on [npm][npm-url] as: `extend` - -``` sh -npm install extend -``` +# extend2 + +Forked from [node-extend], the difference is overriding array as primitive when deep clone. + +[![NPM version][npm-image]][npm-url] +[![build status][travis-image]][travis-url] +[![Test coverage][codecov-image]][codecov-url] +[![David deps][david-image]][david-url] +[![Known Vulnerabilities][snyk-image]][snyk-url] +[![npm download][download-image]][download-url] + +[npm-image]: https://img.shields.io/npm/v/extend2.svg?style=flat-square +[npm-url]: https://npmjs.org/package/extend2 +[travis-image]: https://img.shields.io/travis/eggjs/extend2.svg?style=flat-square +[travis-url]: https://travis-ci.org/eggjs/extend2 +[codecov-image]: https://codecov.io/gh/eggjs/extend2/branch/master/graph/badge.svg +[codecov-url]: https://codecov.io/gh/eggjs/extend2 +[david-image]: https://img.shields.io/david/eggjs/extend2.svg?style=flat-square +[david-url]: https://david-dm.org/eggjs/extend2 +[snyk-image]: https://snyk.io/test/npm/extend2/badge.svg?style=flat-square +[snyk-url]: https://snyk.io/test/npm/extend2 +[download-image]: https://img.shields.io/npm/dm/extend2.svg?style=flat-square +[download-url]: https://npmjs.org/package/extend2 ## Usage -**Syntax:** extend **(** [`deep`], `target`, `object1`, [`objectN`] **)** +```js +const extend = require('extend2'); -*Extend one object with one or more others, returning the modified object.* - -**Example:** - -``` js -var extend = require('extend'); -extend(targetObject, object1, object2); +// for deep clone +extend(true, {}, object1, objectN); ``` -Keep in mind that the target object will be modified, and will be returned from extend(). - -If a boolean true is specified as the first argument, extend performs a deep copy, recursively copying any objects it finds. Otherwise, the copy will share structure with the original object(s). -Undefined properties are not copied. However, properties inherited from the object's prototype will be copied over. -Warning: passing `false` as the first argument is not supported. - -### Arguments - -* `deep` *Boolean* (optional) -If set, the merge becomes recursive (i.e. deep copy). -* `target` *Object* -The object to extend. -* `object1` *Object* -The object that will be merged into the first. -* `objectN` *Object* (Optional) -More objects to merge into the first. - ## License `node-extend` is licensed under the [MIT License][mit-license-url]. @@ -66,16 +41,7 @@ All credit to the jQuery authors for perfecting this amazing utility. Ported to Node.js by [Stefan Thomas][github-justmoon] with contributions by [Jonathan Buchanan][github-insin] and [Jordan Harband][github-ljharb]. -[travis-svg]: https://travis-ci.org/justmoon/node-extend.svg -[travis-url]: https://travis-ci.org/justmoon/node-extend -[npm-url]: https://npmjs.org/package/extend [mit-license-url]: http://opensource.org/licenses/MIT [github-justmoon]: https://github.com/justmoon [github-insin]: https://github.com/insin [github-ljharb]: https://github.com/ljharb -[npm-version-png]: http://versionbadg.es/justmoon/node-extend.svg -[deps-svg]: https://david-dm.org/justmoon/node-extend.svg -[deps-url]: https://david-dm.org/justmoon/node-extend -[dev-deps-svg]: https://david-dm.org/justmoon/node-extend/dev-status.svg -[dev-deps-url]: https://david-dm.org/justmoon/node-extend#info=devDependencies - diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 0000000..2efd0fa --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,16 @@ +environment: + matrix: + - nodejs_version: '4' + - nodejs_version: '6' + - nodejs_version: '7' + +install: + - ps: Install-Product node $env:nodejs_version + - npm i npminstall && node_modules\.bin\npminstall + +test_script: + - node --version + - npm --version + - npm run ci + +build: off diff --git a/index.js b/index.js index ff51827..b4f40f3 100644 --- a/index.js +++ b/index.js @@ -3,83 +3,69 @@ var hasOwn = Object.prototype.hasOwnProperty; var toStr = Object.prototype.toString; -var isArray = function isArray(arr) { - if (typeof Array.isArray === 'function') { - return Array.isArray(arr); - } - - return toStr.call(arr) === '[object Array]'; -}; - var isPlainObject = function isPlainObject(obj) { - if (!obj || toStr.call(obj) !== '[object Object]') { - return false; - } + if (!obj || toStr.call(obj) !== '[object Object]') { + return false; + } - var hasOwnConstructor = hasOwn.call(obj, 'constructor'); - var hasIsPrototypeOf = obj.constructor && obj.constructor.prototype && hasOwn.call(obj.constructor.prototype, 'isPrototypeOf'); - // Not own constructor property must be Object - if (obj.constructor && !hasOwnConstructor && !hasIsPrototypeOf) { - return false; - } + var hasOwnConstructor = hasOwn.call(obj, 'constructor'); + var hasIsPrototypeOf = obj.constructor && obj.constructor.prototype && hasOwn.call(obj.constructor.prototype, 'isPrototypeOf'); + // Not own constructor property must be Object + if (obj.constructor && !hasOwnConstructor && !hasIsPrototypeOf) { + return false; + } - // Own properties are enumerated firstly, so to speed up, - // if last one is own, then all properties are own. - var key; - for (key in obj) { /**/ } + // Own properties are enumerated firstly, so to speed up, + // if last one is own, then all properties are own. + var key; + for (key in obj) { /**/ } - return typeof key === 'undefined' || hasOwn.call(obj, key); + return typeof key === 'undefined' || hasOwn.call(obj, key); }; module.exports = function extend() { - var options, name, src, copy, copyIsArray, clone; - var target = arguments[0]; - var i = 1; - var length = arguments.length; - var deep = false; + var options, name, src, copy, copyIsArray, clone; + var target = arguments[0]; + var i = 1; + var length = arguments.length; + var deep = false; + + // Handle a deep copy situation + if (typeof target === 'boolean') { + deep = target; + target = arguments[1] || {}; + // skip the boolean and the target + i = 2; + } else if ((typeof target !== 'object' && typeof target !== 'function') || target == null) { + target = {}; + } - // Handle a deep copy situation - if (typeof target === 'boolean') { - deep = target; - target = arguments[1] || {}; - // skip the boolean and the target - i = 2; - } else if ((typeof target !== 'object' && typeof target !== 'function') || target == null) { - target = {}; - } + for (; i < length; ++i) { + options = arguments[i]; + // Only deal with non-null/undefined values + if (options == null) continue; - for (; i < length; ++i) { - options = arguments[i]; - // Only deal with non-null/undefined values - if (options != null) { - // Extend the base object - for (name in options) { - src = target[name]; - copy = options[name]; + // Extend the base object + for (name in options) { + src = target[name]; + copy = options[name]; - // Prevent never-ending loop - if (target !== copy) { - // Recurse if we're merging plain objects or arrays - if (deep && copy && (isPlainObject(copy) || (copyIsArray = isArray(copy)))) { - if (copyIsArray) { - copyIsArray = false; - clone = src && isArray(src) ? src : []; - } else { - clone = src && isPlainObject(src) ? src : {}; - } + // Prevent never-ending loop + if (target === copy) continue; - // Never move original objects, clone them - target[name] = extend(deep, clone, copy); + // Recurse if we're merging plain objects + if (deep && copy && isPlainObject(copy)) { + clone = src && isPlainObject(src) ? src : {}; + // Never move original objects, clone them + target[name] = extend(deep, clone, copy); - // Don't bring in undefined values - } else if (typeof copy !== 'undefined') { - target[name] = copy; - } - } - } - } - } + // Don't bring in undefined values + } else if (typeof copy !== 'undefined') { + target[name] = copy; + } + } + } - // Return the modified object - return target; + // Return the modified object + return target; }; diff --git a/package.json b/package.json index a05c915..906e580 100644 --- a/package.json +++ b/package.json @@ -1,41 +1,46 @@ { - "name": "extend", - "author": "Stefan Thomas (http://www.justmoon.net)", - "version": "3.0.0", - "description": "Port of jQuery.extend for node.js and the browser", - "main": "index", - "scripts": { - "test": "npm run lint && npm run tests-only && npm run coverage-quiet", - "tests-only": "node test", - "coverage": "covert test/index.js", - "coverage-quiet": "covert test/index.js --quiet", - "lint": "npm run jscs && npm run eslint", - "jscs": "jscs *.js */*.js", - "eslint": "eslint *.js */*.js" - }, - "contributors": [ - { - "name": "Jordan Harband", - "url": "https://github.com/ljharb" - } - ], - "keywords": [ - "extend", - "clone", - "merge" - ], - "repository": { - "type": "git", - "url": "https://github.com/justmoon/node-extend.git" - }, - "dependencies": {}, - "devDependencies": { - "tape": "^4.6.0", - "covert": "^1.1.0", - "jscs": "^3.0.7", - "eslint": "^3.2.2", - "@ljharb/eslint-config": "^6.0.0" - }, - "license": "MIT" + "name": "extend2", + "author": "Stefan Thomas (http://www.justmoon.net)", + "version": "1.0.0", + "description": "Port of jQuery.extend for node.js and the browser", + "main": "index", + "scripts": { + "test": "npm run lint && npm run tests-only && npm run coverage-quiet", + "tests-only": "node test", + "coverage": "covert test/index.js", + "coverage-quiet": "covert test/index.js --quiet", + "lint": "npm run eslint", + "eslint": "eslint *.js */*.js", + "ci": "npm run test" + }, + "contributors": [ + { + "name": "Jordan Harband", + "url": "https://github.com/ljharb" + } + ], + "keywords": [ + "extend", + "clone", + "merge" + ], + "repository": { + "type": "git", + "url": "https://github.com/eggjs/extend2.git" + }, + "dependencies": {}, + "devDependencies": { + "covert": "^1.1.0", + "egg-ci": "^1.5.0", + "eslint": "^3.2.2", + "eslint-config-egg": "^3.2.0", + "tape": "^4.6.0" + }, + "license": "MIT", + "files": [ + "index.js" + ], + "ci": { + "version": "4, 6, 7" + } } - diff --git a/test/.eslintrc b/test/.eslintrc deleted file mode 100644 index 7128f5a..0000000 --- a/test/.eslintrc +++ /dev/null @@ -1,5 +0,0 @@ -{ - "rules": { - "max-lines": 0 - } -} diff --git a/test/index.js b/test/index.js index 92a73a3..8c4fd32 100644 --- a/test/index.js +++ b/test/index.js @@ -11,611 +11,611 @@ var date = new Date(81, 4, 13); var Foo = function () {}; var obj = { - str: str, - integer: integer, - arr: arr, - date: date, - constructor: 'fake', - isPrototypeOf: 'not a function', - foo: new Foo() + str: str, + integer: integer, + arr: arr, + date: date, + constructor: 'fake', + isPrototypeOf: 'not a function', + foo: new Foo() }; var deep = { - ori: obj, - layer: { - integer: 10, - str: 'str', - date: new Date(84, 5, 12), - arr: [101, 'dude', new Date(82, 10, 4)], - deep: { - str: obj.str, - integer: integer, - arr: obj.arr, - date: new Date(81, 7, 4) - } - } + ori: obj, + layer: { + integer: 10, + str: 'str', + date: new Date(84, 5, 12), + arr: [101, 'dude', new Date(82, 10, 4)], + deep: { + str: obj.str, + integer: integer, + arr: obj.arr, + date: new Date(81, 7, 4) + } + } }; test('missing arguments', function (t) { - t.deepEqual(extend(undefined, { a: 1 }), { a: 1 }, 'missing first argument is second argument'); - t.deepEqual(extend({ a: 1 }), { a: 1 }, 'missing second argument is first argument'); - t.deepEqual(extend(true, undefined, { a: 1 }), { a: 1 }, 'deep: missing first argument is second argument'); - t.deepEqual(extend(true, { a: 1 }), { a: 1 }, 'deep: missing second argument is first argument'); - t.deepEqual(extend(), {}, 'no arguments is object'); - t.end(); + t.deepEqual(extend(undefined, { a: 1 }), { a: 1 }, 'missing first argument is second argument'); + t.deepEqual(extend({ a: 1 }), { a: 1 }, 'missing second argument is first argument'); + t.deepEqual(extend(true, undefined, { a: 1 }), { a: 1 }, 'deep: missing first argument is second argument'); + t.deepEqual(extend(true, { a: 1 }), { a: 1 }, 'deep: missing second argument is first argument'); + t.deepEqual(extend(), {}, 'no arguments is object'); + t.end(); }); test('merge string with string', function (t) { - var ori = 'what u gonna say'; - var target = extend(ori, str); - var expectedTarget = { - 0: 'm', - 1: 'e', - 2: ' ', - 3: 'a', - 4: ' ', - 5: 't', - 6: 'e', - 7: 's', - 8: 't' - }; - - t.equal(ori, 'what u gonna say', 'original string 1 is unchanged'); - t.equal(str, 'me a test', 'original string 2 is unchanged'); - t.deepEqual(target, expectedTarget, 'string + string is merged object form of string'); - t.end(); + var ori = 'what u gonna say'; + var target = extend(ori, str); + var expectedTarget = { + 0: 'm', + 1: 'e', + 2: ' ', + 3: 'a', + 4: ' ', + 5: 't', + 6: 'e', + 7: 's', + 8: 't' + }; + + t.equal(ori, 'what u gonna say', 'original string 1 is unchanged'); + t.equal(str, 'me a test', 'original string 2 is unchanged'); + t.deepEqual(target, expectedTarget, 'string + string is merged object form of string'); + t.end(); }); test('merge string with number', function (t) { - var ori = 'what u gonna say'; - var target = extend(ori, 10); + var ori = 'what u gonna say'; + var target = extend(ori, 10); - t.equal(ori, 'what u gonna say', 'original string is unchanged'); - t.deepEqual(target, {}, 'string + number is empty object'); + t.equal(ori, 'what u gonna say', 'original string is unchanged'); + t.deepEqual(target, {}, 'string + number is empty object'); - t.end(); + t.end(); }); test('merge string with array', function (t) { - var ori = 'what u gonna say'; - var target = extend(ori, arr); - - t.equal(ori, 'what u gonna say', 'original string is unchanged'); - t.deepEqual(arr, [1, 'what', new Date(81, 8, 4)], 'array is unchanged'); - t.deepEqual(target, { - 0: 1, - 1: 'what', - 2: new Date(81, 8, 4) - }, 'string + array is array'); - t.end(); + var ori = 'what u gonna say'; + var target = extend(ori, arr); + + t.equal(ori, 'what u gonna say', 'original string is unchanged'); + t.deepEqual(arr, [1, 'what', new Date(81, 8, 4)], 'array is unchanged'); + t.deepEqual(target, { + 0: 1, + 1: 'what', + 2: new Date(81, 8, 4) + }, 'string + array is array'); + t.end(); }); test('merge string with date', function (t) { - var ori = 'what u gonna say'; - var target = extend(ori, date); - - var testDate = new Date(81, 4, 13); - t.equal(ori, 'what u gonna say', 'original string is unchanged'); - t.deepEqual(date, testDate, 'date is unchanged'); - t.deepEqual(target, testDate, 'string + date is date'); - t.end(); + var ori = 'what u gonna say'; + var target = extend(ori, date); + + var testDate = new Date(81, 4, 13); + t.equal(ori, 'what u gonna say', 'original string is unchanged'); + t.deepEqual(date, testDate, 'date is unchanged'); + t.deepEqual(target, testDate, 'string + date is date'); + t.end(); }); test('merge string with obj', function (t) { - var ori = 'what u gonna say'; - var target = extend(ori, obj); - - t.equal(ori, 'what u gonna say', 'original string is unchanged'); - var testObj = { - str: 'me a test', - integer: 10, - arr: [1, 'what', new Date(81, 8, 4)], - date: new Date(81, 4, 13), - constructor: 'fake', - isPrototypeOf: 'not a function', - foo: new Foo() - }; - t.deepEqual(obj, testObj, 'original obj is unchanged'); - t.deepEqual(target, testObj, 'string + obj is obj'); - t.end(); + var ori = 'what u gonna say'; + var target = extend(ori, obj); + + t.equal(ori, 'what u gonna say', 'original string is unchanged'); + var testObj = { + str: 'me a test', + integer: 10, + arr: [1, 'what', new Date(81, 8, 4)], + date: new Date(81, 4, 13), + constructor: 'fake', + isPrototypeOf: 'not a function', + foo: new Foo() + }; + t.deepEqual(obj, testObj, 'original obj is unchanged'); + t.deepEqual(target, testObj, 'string + obj is obj'); + t.end(); }); test('merge number with string', function (t) { - var ori = 20; - var target = extend(ori, str); - - t.equal(ori, 20, 'number is unchanged'); - t.equal(str, 'me a test', 'string is unchanged'); - t.deepEqual(target, { - 0: 'm', - 1: 'e', - 2: ' ', - 3: 'a', - 4: ' ', - 5: 't', - 6: 'e', - 7: 's', - 8: 't' - }, 'number + string is object form of string'); - t.end(); + var ori = 20; + var target = extend(ori, str); + + t.equal(ori, 20, 'number is unchanged'); + t.equal(str, 'me a test', 'string is unchanged'); + t.deepEqual(target, { + 0: 'm', + 1: 'e', + 2: ' ', + 3: 'a', + 4: ' ', + 5: 't', + 6: 'e', + 7: 's', + 8: 't' + }, 'number + string is object form of string'); + t.end(); }); test('merge number with number', function (t) { - t.deepEqual(extend(20, 10), {}, 'number + number is empty object'); - t.end(); + t.deepEqual(extend(20, 10), {}, 'number + number is empty object'); + t.end(); }); test('merge number with array', function (t) { - var target = extend(20, arr); - - t.deepEqual(arr, [1, 'what', new Date(81, 8, 4)], 'array is unchanged'); - t.deepEqual(target, { - 0: 1, - 1: 'what', - 2: new Date(81, 8, 4) - }, 'number + arr is object with array contents'); - t.end(); + var target = extend(20, arr); + + t.deepEqual(arr, [1, 'what', new Date(81, 8, 4)], 'array is unchanged'); + t.deepEqual(target, { + 0: 1, + 1: 'what', + 2: new Date(81, 8, 4) + }, 'number + arr is object with array contents'); + t.end(); }); test('merge number with date', function (t) { - var target = extend(20, date); - var testDate = new Date(81, 4, 13); + var target = extend(20, date); + var testDate = new Date(81, 4, 13); - t.deepEqual(date, testDate, 'original date is unchanged'); - t.deepEqual(target, testDate, 'number + date is date'); - t.end(); + t.deepEqual(date, testDate, 'original date is unchanged'); + t.deepEqual(target, testDate, 'number + date is date'); + t.end(); }); test('merge number with object', function (t) { - var target = extend(20, obj); - var testObj = { - str: 'me a test', - integer: 10, - arr: [1, 'what', new Date(81, 8, 4)], - date: new Date(81, 4, 13), - constructor: 'fake', - isPrototypeOf: 'not a function', - foo: new Foo() - }; - - t.deepEqual(obj, testObj, 'obj is unchanged'); - t.deepEqual(target, testObj, 'number + obj is obj'); - t.end(); + var target = extend(20, obj); + var testObj = { + str: 'me a test', + integer: 10, + arr: [1, 'what', new Date(81, 8, 4)], + date: new Date(81, 4, 13), + constructor: 'fake', + isPrototypeOf: 'not a function', + foo: new Foo() + }; + + t.deepEqual(obj, testObj, 'obj is unchanged'); + t.deepEqual(target, testObj, 'number + obj is obj'); + t.end(); }); test('merge array with string', function (t) { - var ori = [1, 2, 3, 4, 5, 6]; - var target = extend(ori, str); - - t.deepEqual(ori, str.split(''), 'array is changed to be an array of string chars'); - t.equal(str, 'me a test', 'string is unchanged'); - t.deepEqual(target, { - 0: 'm', - 1: 'e', - 2: ' ', - 3: 'a', - 4: ' ', - 5: 't', - 6: 'e', - 7: 's', - 8: 't' - }, 'array + string is object form of string'); - t.end(); + var ori = [1, 2, 3, 4, 5, 6]; + var target = extend(ori, str); + + t.deepEqual(ori, str.split(''), 'array is changed to be an array of string chars'); + t.equal(str, 'me a test', 'string is unchanged'); + t.deepEqual(target, { + 0: 'm', + 1: 'e', + 2: ' ', + 3: 'a', + 4: ' ', + 5: 't', + 6: 'e', + 7: 's', + 8: 't' + }, 'array + string is object form of string'); + t.end(); }); test('merge array with number', function (t) { - var ori = [1, 2, 3, 4, 5, 6]; - var target = extend(ori, 10); + var ori = [1, 2, 3, 4, 5, 6]; + var target = extend(ori, 10); - t.deepEqual(ori, [1, 2, 3, 4, 5, 6], 'array is unchanged'); - t.deepEqual(target, ori, 'array + number is array'); - t.end(); + t.deepEqual(ori, [1, 2, 3, 4, 5, 6], 'array is unchanged'); + t.deepEqual(target, ori, 'array + number is array'); + t.end(); }); test('merge array with array', function (t) { - var ori = [1, 2, 3, 4, 5, 6]; - var target = extend(ori, arr); - var testDate = new Date(81, 8, 4); - var expectedTarget = [1, 'what', testDate, 4, 5, 6]; - - t.deepEqual(ori, expectedTarget, 'array + array merges arrays; changes first array'); - t.deepEqual(arr, [1, 'what', testDate], 'second array is unchanged'); - t.deepEqual(target, expectedTarget, 'array + array is merged array'); - t.end(); + var ori = [1, 2, 3, 4, 5, 6]; + var target = extend(ori, arr); + var testDate = new Date(81, 8, 4); + var expectedTarget = [1, 'what', testDate, 4, 5, 6]; + + t.deepEqual(ori, expectedTarget, 'array + array merges arrays; changes first array'); + t.deepEqual(arr, [1, 'what', testDate], 'second array is unchanged'); + t.deepEqual(target, expectedTarget, 'array + array is merged array'); + t.end(); }); test('merge array with date', function (t) { - var ori = [1, 2, 3, 4, 5, 6]; - var target = extend(ori, date); - var testDate = new Date(81, 4, 13); - var testArray = [1, 2, 3, 4, 5, 6]; - - t.deepEqual(ori, testArray, 'array is unchanged'); - t.deepEqual(date, testDate, 'date is unchanged'); - t.deepEqual(target, testArray, 'array + date is array'); - t.end(); + var ori = [1, 2, 3, 4, 5, 6]; + var target = extend(ori, date); + var testDate = new Date(81, 4, 13); + var testArray = [1, 2, 3, 4, 5, 6]; + + t.deepEqual(ori, testArray, 'array is unchanged'); + t.deepEqual(date, testDate, 'date is unchanged'); + t.deepEqual(target, testArray, 'array + date is array'); + t.end(); }); test('merge array with object', function (t) { - var ori = [1, 2, 3, 4, 5, 6]; - var target = extend(ori, obj); - var testObject = { - str: 'me a test', - integer: 10, - arr: [1, 'what', new Date(81, 8, 4)], - date: new Date(81, 4, 13), - constructor: 'fake', - isPrototypeOf: 'not a function', - foo: new Foo() - }; - - t.deepEqual(obj, testObject, 'obj is unchanged'); - t.equal(ori.length, 6, 'array has proper length'); - t.equal(ori.str, obj.str, 'array has obj.str property'); - t.equal(ori.integer, obj.integer, 'array has obj.integer property'); - t.deepEqual(ori.arr, obj.arr, 'array has obj.arr property'); - t.equal(ori.date, obj.date, 'array has obj.date property'); - - t.equal(target.length, 6, 'target has proper length'); - t.equal(target.str, obj.str, 'target has obj.str property'); - t.equal(target.integer, obj.integer, 'target has obj.integer property'); - t.deepEqual(target.arr, obj.arr, 'target has obj.arr property'); - t.equal(target.date, obj.date, 'target has obj.date property'); - t.end(); + var ori = [1, 2, 3, 4, 5, 6]; + var target = extend(ori, obj); + var testObject = { + str: 'me a test', + integer: 10, + arr: [1, 'what', new Date(81, 8, 4)], + date: new Date(81, 4, 13), + constructor: 'fake', + isPrototypeOf: 'not a function', + foo: new Foo() + }; + + t.deepEqual(obj, testObject, 'obj is unchanged'); + t.equal(ori.length, 6, 'array has proper length'); + t.equal(ori.str, obj.str, 'array has obj.str property'); + t.equal(ori.integer, obj.integer, 'array has obj.integer property'); + t.deepEqual(ori.arr, obj.arr, 'array has obj.arr property'); + t.equal(ori.date, obj.date, 'array has obj.date property'); + + t.equal(target.length, 6, 'target has proper length'); + t.equal(target.str, obj.str, 'target has obj.str property'); + t.equal(target.integer, obj.integer, 'target has obj.integer property'); + t.deepEqual(target.arr, obj.arr, 'target has obj.arr property'); + t.equal(target.date, obj.date, 'target has obj.date property'); + t.end(); }); test('merge date with string', function (t) { - var ori = new Date(81, 9, 20); - var target = extend(ori, str); - var testObject = { - 0: 'm', - 1: 'e', - 2: ' ', - 3: 'a', - 4: ' ', - 5: 't', - 6: 'e', - 7: 's', - 8: 't' - }; - - t.deepEqual(ori, testObject, 'date is changed to object form of string'); - t.equal(str, 'me a test', 'string is unchanged'); - t.deepEqual(target, testObject, 'date + string is object form of string'); - t.end(); + var ori = new Date(81, 9, 20); + var target = extend(ori, str); + var testObject = { + 0: 'm', + 1: 'e', + 2: ' ', + 3: 'a', + 4: ' ', + 5: 't', + 6: 'e', + 7: 's', + 8: 't' + }; + + t.deepEqual(ori, testObject, 'date is changed to object form of string'); + t.equal(str, 'me a test', 'string is unchanged'); + t.deepEqual(target, testObject, 'date + string is object form of string'); + t.end(); }); test('merge date with number', function (t) { - var ori = new Date(81, 9, 20); - var target = extend(ori, 10); + var ori = new Date(81, 9, 20); + var target = extend(ori, 10); - t.deepEqual(ori, {}, 'date is changed to empty object'); - t.deepEqual(target, {}, 'date + number is empty object'); - t.end(); + t.deepEqual(ori, {}, 'date is changed to empty object'); + t.deepEqual(target, {}, 'date + number is empty object'); + t.end(); }); test('merge date with array', function (t) { - var ori = new Date(81, 9, 20); - var target = extend(ori, arr); - var testDate = new Date(81, 9, 20); - var testArray = [1, 'what', new Date(81, 8, 4)]; - - t.deepEqual(ori, testDate, 'date is unchanged'); - t.deepEqual(arr, testArray, 'array is unchanged'); - t.deepEqual(target, testDate, 'date + array is date'); - t.end(); + var ori = new Date(81, 9, 20); + var target = extend(ori, arr); + var testDate = new Date(81, 9, 20); + var testArray = [1, 'what', new Date(81, 8, 4)]; + + t.deepEqual(ori, testDate, 'date is unchanged'); + t.deepEqual(arr, testArray, 'array is unchanged'); + t.deepEqual(target, testDate, 'date + array is date'); + t.end(); }); test('merge date with date', function (t) { - var ori = new Date(81, 9, 20); - var target = extend(ori, date); + var ori = new Date(81, 9, 20); + var target = extend(ori, date); - t.deepEqual(ori, {}, 'date is empty object'); - t.deepEqual(target, {}, 'date + date is empty object'); - t.end(); + t.deepEqual(ori, {}, 'date is empty object'); + t.deepEqual(target, {}, 'date + date is empty object'); + t.end(); }); test('merge date with object', function (t) { - var ori = new Date(81, 9, 20); - var target = extend(ori, obj); - var testDate = new Date(81, 8, 4); - var testObject = { - str: 'me a test', - integer: 10, - arr: [1, 'what', testDate], - date: new Date(81, 4, 13), - constructor: 'fake', - isPrototypeOf: 'not a function', - foo: new Foo() - }; - - t.deepEqual(obj, testObject, 'original object is unchanged'); - t.deepEqual(ori, testObject, 'date becomes original object'); - t.deepEqual(target, testObject, 'date + object is object'); - t.end(); + var ori = new Date(81, 9, 20); + var target = extend(ori, obj); + var testDate = new Date(81, 8, 4); + var testObject = { + str: 'me a test', + integer: 10, + arr: [1, 'what', testDate], + date: new Date(81, 4, 13), + constructor: 'fake', + isPrototypeOf: 'not a function', + foo: new Foo() + }; + + t.deepEqual(obj, testObject, 'original object is unchanged'); + t.deepEqual(ori, testObject, 'date becomes original object'); + t.deepEqual(target, testObject, 'date + object is object'); + t.end(); }); test('merge object with string', function (t) { - var testDate = new Date(81, 7, 26); - var ori = { - str: 'no shit', - integer: 76, - arr: [1, 2, 3, 4], - date: testDate - }; - var target = extend(ori, str); - var testObj = { - 0: 'm', - 1: 'e', - 2: ' ', - 3: 'a', - 4: ' ', - 5: 't', - 6: 'e', - 7: 's', - 8: 't', - str: 'no shit', - integer: 76, - arr: [1, 2, 3, 4], - date: testDate - }; - - t.deepEqual(ori, testObj, 'original object updated'); - t.equal(str, 'me a test', 'string is unchanged'); - t.deepEqual(target, testObj, 'object + string is object + object form of string'); - t.end(); + var testDate = new Date(81, 7, 26); + var ori = { + str: 'no shit', + integer: 76, + arr: [1, 2, 3, 4], + date: testDate + }; + var target = extend(ori, str); + var testObj = { + 0: 'm', + 1: 'e', + 2: ' ', + 3: 'a', + 4: ' ', + 5: 't', + 6: 'e', + 7: 's', + 8: 't', + str: 'no shit', + integer: 76, + arr: [1, 2, 3, 4], + date: testDate + }; + + t.deepEqual(ori, testObj, 'original object updated'); + t.equal(str, 'me a test', 'string is unchanged'); + t.deepEqual(target, testObj, 'object + string is object + object form of string'); + t.end(); }); test('merge object with number', function (t) { - var ori = { - str: 'no shit', - integer: 76, - arr: [1, 2, 3, 4], - date: new Date(81, 7, 26) - }; - var testObject = { - str: 'no shit', - integer: 76, - arr: [1, 2, 3, 4], - date: new Date(81, 7, 26) - }; - var target = extend(ori, 10); - t.deepEqual(ori, testObject, 'object is unchanged'); - t.deepEqual(target, testObject, 'object + number is object'); - t.end(); + var ori = { + str: 'no shit', + integer: 76, + arr: [1, 2, 3, 4], + date: new Date(81, 7, 26) + }; + var testObject = { + str: 'no shit', + integer: 76, + arr: [1, 2, 3, 4], + date: new Date(81, 7, 26) + }; + var target = extend(ori, 10); + t.deepEqual(ori, testObject, 'object is unchanged'); + t.deepEqual(target, testObject, 'object + number is object'); + t.end(); }); test('merge object with array', function (t) { - var ori = { - str: 'no shit', - integer: 76, - arr: [1, 2, 3, 4], - date: new Date(81, 7, 26) - }; - var target = extend(ori, arr); - var testObject = { - 0: 1, - 1: 'what', - 2: new Date(81, 8, 4), - str: 'no shit', - integer: 76, - arr: [1, 2, 3, 4], - date: new Date(81, 7, 26) - }; - - t.deepEqual(ori, testObject, 'original object is merged'); - t.deepEqual(arr, [1, 'what', testObject[2]], 'array is unchanged'); - t.deepEqual(target, testObject, 'object + array is merged object'); - t.end(); + var ori = { + str: 'no shit', + integer: 76, + arr: [1, 2, 3, 4], + date: new Date(81, 7, 26) + }; + var target = extend(ori, arr); + var testObject = { + 0: 1, + 1: 'what', + 2: new Date(81, 8, 4), + str: 'no shit', + integer: 76, + arr: [1, 2, 3, 4], + date: new Date(81, 7, 26) + }; + + t.deepEqual(ori, testObject, 'original object is merged'); + t.deepEqual(arr, [1, 'what', testObject[2]], 'array is unchanged'); + t.deepEqual(target, testObject, 'object + array is merged object'); + t.end(); }); test('merge object with date', function (t) { - var ori = { - str: 'no shit', - integer: 76, - arr: [1, 2, 3, 4], - date: new Date(81, 7, 26) - }; - var target = extend(ori, date); - var testObject = { - str: 'no shit', - integer: 76, - arr: [1, 2, 3, 4], - date: new Date(81, 7, 26) - }; - - t.deepEqual(ori, testObject, 'original object is unchanged'); - t.deepEqual(date, new Date(81, 4, 13), 'date is unchanged'); - t.deepEqual(target, testObject, 'object + date is object'); - t.end(); + var ori = { + str: 'no shit', + integer: 76, + arr: [1, 2, 3, 4], + date: new Date(81, 7, 26) + }; + var target = extend(ori, date); + var testObject = { + str: 'no shit', + integer: 76, + arr: [1, 2, 3, 4], + date: new Date(81, 7, 26) + }; + + t.deepEqual(ori, testObject, 'original object is unchanged'); + t.deepEqual(date, new Date(81, 4, 13), 'date is unchanged'); + t.deepEqual(target, testObject, 'object + date is object'); + t.end(); }); test('merge object with object', function (t) { - var ori = { - str: 'no shit', - integer: 76, - arr: [1, 2, 3, 4], - date: new Date(81, 7, 26), - foo: 'bar' - }; - var target = extend(ori, obj); - var expectedObj = { - str: 'me a test', - integer: 10, - arr: [1, 'what', new Date(81, 8, 4)], - date: new Date(81, 4, 13), - constructor: 'fake', - isPrototypeOf: 'not a function', - foo: new Foo() - }; - var expectedTarget = { - str: 'me a test', - integer: 10, - arr: [1, 'what', new Date(81, 8, 4)], - date: new Date(81, 4, 13), - constructor: 'fake', - isPrototypeOf: 'not a function', - foo: new Foo() - }; - - t.deepEqual(obj, expectedObj, 'obj is unchanged'); - t.deepEqual(ori, expectedTarget, 'original has been merged'); - t.deepEqual(target, expectedTarget, 'object + object is merged object'); - t.end(); + var ori = { + str: 'no shit', + integer: 76, + arr: [1, 2, 3, 4], + date: new Date(81, 7, 26), + foo: 'bar' + }; + var target = extend(ori, obj); + var expectedObj = { + str: 'me a test', + integer: 10, + arr: [1, 'what', new Date(81, 8, 4)], + date: new Date(81, 4, 13), + constructor: 'fake', + isPrototypeOf: 'not a function', + foo: new Foo() + }; + var expectedTarget = { + str: 'me a test', + integer: 10, + arr: [1, 'what', new Date(81, 8, 4)], + date: new Date(81, 4, 13), + constructor: 'fake', + isPrototypeOf: 'not a function', + foo: new Foo() + }; + + t.deepEqual(obj, expectedObj, 'obj is unchanged'); + t.deepEqual(ori, expectedTarget, 'original has been merged'); + t.deepEqual(target, expectedTarget, 'object + object is merged object'); + t.end(); }); test('deep clone', function (t) { - var ori = { - str: 'no shit', - integer: 76, - arr: [1, 2, 3, 4], - date: new Date(81, 7, 26), - layer: { deep: { integer: 42 } } - }; - var target = extend(true, ori, deep); - - t.deepEqual(ori, { - str: 'no shit', - integer: 76, - arr: [1, 2, 3, 4], - date: new Date(81, 7, 26), - ori: { - str: 'me a test', - integer: 10, - arr: [1, 'what', new Date(81, 8, 4)], - date: new Date(81, 4, 13), - constructor: 'fake', - isPrototypeOf: 'not a function', - foo: new Foo() - }, - layer: { - integer: 10, - str: 'str', - date: new Date(84, 5, 12), - arr: [101, 'dude', new Date(82, 10, 4)], - deep: { - str: 'me a test', - integer: 10, - arr: [1, 'what', new Date(81, 8, 4)], - date: new Date(81, 7, 4) - } - } - }, 'original object is merged'); - t.deepEqual(deep, { - ori: { - str: 'me a test', - integer: 10, - arr: [1, 'what', new Date(81, 8, 4)], - date: new Date(81, 4, 13), - constructor: 'fake', - isPrototypeOf: 'not a function', - foo: new Foo() - }, - layer: { - integer: 10, - str: 'str', - date: new Date(84, 5, 12), - arr: [101, 'dude', new Date(82, 10, 4)], - deep: { - str: 'me a test', - integer: 10, - arr: [1, 'what', new Date(81, 8, 4)], - date: new Date(81, 7, 4) - } - } - }, 'deep is unchanged'); - t.deepEqual(target, { - str: 'no shit', - integer: 76, - arr: [1, 2, 3, 4], - date: new Date(81, 7, 26), - ori: { - str: 'me a test', - integer: 10, - arr: [1, 'what', new Date(81, 8, 4)], - date: new Date(81, 4, 13), - constructor: 'fake', - isPrototypeOf: 'not a function', - foo: new Foo() - }, - layer: { - integer: 10, - str: 'str', - date: new Date(84, 5, 12), - arr: [101, 'dude', new Date(82, 10, 4)], - deep: { - str: 'me a test', - integer: 10, - arr: [1, 'what', new Date(81, 8, 4)], - date: new Date(81, 7, 4) - } - } - }, 'deep + object + object is deeply merged object'); - - target.layer.deep = 339; - t.deepEqual(deep, { - ori: { - str: 'me a test', - integer: 10, - arr: [1, 'what', new Date(81, 8, 4)], - date: new Date(81, 4, 13), - constructor: 'fake', - isPrototypeOf: 'not a function', - foo: new Foo() - }, - layer: { - integer: 10, - str: 'str', - date: new Date(84, 5, 12), - arr: [101, 'dude', new Date(82, 10, 4)], - deep: { - str: 'me a test', - integer: 10, - arr: [1, 'what', new Date(81, 8, 4)], - date: new Date(81, 7, 4) - } - } - }, 'deep is unchanged after setting target property'); - // ----- NEVER USE EXTEND WITH THE ABOVE SITUATION ------------------------------ - t.end(); + var ori = { + str: 'no shit', + integer: 76, + arr: [1, 2, 3, 4], + date: new Date(81, 7, 26), + layer: { deep: { integer: 42 } } + }; + var target = extend(true, ori, deep); + + t.deepEqual(ori, { + str: 'no shit', + integer: 76, + arr: [1, 2, 3, 4], + date: new Date(81, 7, 26), + ori: { + str: 'me a test', + integer: 10, + arr: [1, 'what', new Date(81, 8, 4)], + date: new Date(81, 4, 13), + constructor: 'fake', + isPrototypeOf: 'not a function', + foo: new Foo() + }, + layer: { + integer: 10, + str: 'str', + date: new Date(84, 5, 12), + arr: [101, 'dude', new Date(82, 10, 4)], + deep: { + str: 'me a test', + integer: 10, + arr: [1, 'what', new Date(81, 8, 4)], + date: new Date(81, 7, 4) + } + } + }, 'original object is merged'); + t.deepEqual(deep, { + ori: { + str: 'me a test', + integer: 10, + arr: [1, 'what', new Date(81, 8, 4)], + date: new Date(81, 4, 13), + constructor: 'fake', + isPrototypeOf: 'not a function', + foo: new Foo() + }, + layer: { + integer: 10, + str: 'str', + date: new Date(84, 5, 12), + arr: [101, 'dude', new Date(82, 10, 4)], + deep: { + str: 'me a test', + integer: 10, + arr: [1, 'what', new Date(81, 8, 4)], + date: new Date(81, 7, 4) + } + } + }, 'deep is unchanged'); + t.deepEqual(target, { + str: 'no shit', + integer: 76, + arr: [1, 2, 3, 4], + date: new Date(81, 7, 26), + ori: { + str: 'me a test', + integer: 10, + arr: [1, 'what', new Date(81, 8, 4)], + date: new Date(81, 4, 13), + constructor: 'fake', + isPrototypeOf: 'not a function', + foo: new Foo() + }, + layer: { + integer: 10, + str: 'str', + date: new Date(84, 5, 12), + arr: [101, 'dude', new Date(82, 10, 4)], + deep: { + str: 'me a test', + integer: 10, + arr: [1, 'what', new Date(81, 8, 4)], + date: new Date(81, 7, 4) + } + } + }, 'deep + object + object is deeply merged object'); + + target.layer.deep = 339; + t.deepEqual(deep, { + ori: { + str: 'me a test', + integer: 10, + arr: [1, 'what', new Date(81, 8, 4)], + date: new Date(81, 4, 13), + constructor: 'fake', + isPrototypeOf: 'not a function', + foo: new Foo() + }, + layer: { + integer: 10, + str: 'str', + date: new Date(84, 5, 12), + arr: [101, 'dude', new Date(82, 10, 4)], + deep: { + str: 'me a test', + integer: 10, + arr: [1, 'what', new Date(81, 8, 4)], + date: new Date(81, 7, 4) + } + } + }, 'deep is unchanged after setting target property'); + // ----- NEVER USE EXTEND WITH THE ABOVE SITUATION ------------------------------ + t.end(); }); -test('deep clone; arrays are merged', function (t) { - var defaults = { arr: [1, 2, 3] }; - var override = { arr: ['x'] }; - var expectedTarget = { arr: ['x', 2, 3] }; +test('deep clone; arrays are override', function (t) { + var defaults = { arr: [1, 2, 3] }; + var override = { arr: ['x'] }; + var expectedTarget = { arr: ['x'] }; - var target = extend(true, defaults, override); + var target = extend(true, defaults, override); - t.deepEqual(target, expectedTarget, 'arrays are merged'); - t.end(); + t.deepEqual(target, expectedTarget, 'arrays are merged'); + t.end(); }); test('deep clone === false; objects merged normally', function (t) { - var defaults = { a: 1 }; - var override = { a: 2 }; - var target = extend(false, defaults, override); - t.deepEqual(target, override, 'deep === false handled normally'); - t.end(); + var defaults = { a: 1 }; + var override = { a: 2 }; + var target = extend(false, defaults, override); + t.deepEqual(target, override, 'deep === false handled normally'); + t.end(); }); test('pass in null; should create a valid object', function (t) { - var override = { a: 1 }; - var target = extend(null, override); - t.deepEqual(target, override, 'null object handled normally'); - t.end(); + var override = { a: 1 }; + var target = extend(null, override); + t.deepEqual(target, override, 'null object handled normally'); + t.end(); }); test('works without Array.isArray', function (t) { - var savedIsArray = Array.isArray; - Array.isArray = false; // don't delete, to preserve enumerability - var target = []; - var source = [1, [2], { 3: true }]; - t.deepEqual( - extend(true, target, source), - [1, [2], { 3: true }], - 'It works without Array.isArray' - ); - Array.isArray = savedIsArray; - t.end(); + var savedIsArray = Array.isArray; + Array.isArray = false; // don't delete, to preserve enumerability + var target = []; + var source = [1, [2], { 3: true }]; + t.deepEqual( + extend(true, target, source), + [1, [2], { 3: true }], + 'It works without Array.isArray' + ); + Array.isArray = savedIsArray; + t.end(); });