Skip to content
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
214 changes: 115 additions & 99 deletions lib/deep-extend.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2013-2015 Viacheslav Lotsmanov
* Copyright (c) 2013-2016 Viacheslav Lotsmanov
* Copyright (c) 2016 Andrew Fatkulin
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
Expand All @@ -25,120 +26,135 @@
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

'use strict';

function isSpecificValue(val) {
return (
val instanceof Buffer
|| val instanceof Date
|| val instanceof RegExp
) ? true : false;
}

function cloneSpecificValue(val) {
if (val instanceof Buffer) {
var x = new Buffer(val.length);
val.copy(x);
return x;
} else if (val instanceof Date) {
return new Date(val.getTime());
} else if (val instanceof RegExp) {
return new RegExp(val);
} else {
throw new Error('Unexpected situation');
}
}

/**
* Recursive cloning array.
*/
function deepCloneArray(arr) {
var clone = [];
arr.forEach(function (item, index) {
if (typeof item === 'object' && item !== null) {
if (Array.isArray(item)) {
clone[index] = deepCloneArray(item);
} else if (isSpecificValue(item)) {
clone[index] = cloneSpecificValue(item);
} else {
clone[index] = deepExtend({}, item);
}
} else {
clone[index] = item;
}
});
return clone;
}

/**
* Extening object that entered in first argument.
*
* Returns extended object or false if have no target object or incorrect type.
*
* If you wish to clone source object (without modify it), just use empty new
* object as first argument, like this:
* deepExtend({}, yourObj_1, [yourObj_N]);
*/
var deepExtend = module.exports = function (/*obj_1, [obj_2], [obj_N]*/) {
if (arguments.length < 1 || typeof arguments[0] !== 'object') {
return false;
}
(function (name, definition) {

if (arguments.length < 2) {
return arguments[0];
}
if (typeof module !== 'undefined' && module.exports) module.exports = definition();
else if (typeof define !== 'undefined' && typeof define == 'function' && typeof define.amd == 'object') define(definition);
else window[name] = definition();
Copy link
Owner

@unclechu unclechu Aug 18, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. broken indentation
  2. follow style guide and wrap this conditions with brackets {} and put each expression on new line
  3. check if we have window as object typeof window === 'object' and if we don't have throw exception new Error('Unknown platform')
  4. line length limit is 80 symbols

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 Good catch. Thanks.


var target = arguments[0];
})('deepExtend', function () {

// convert arguments to array and cut off target object
var args = Array.prototype.slice.call(arguments, 1);
'use strict';

var val, src, clone;
function isSpecificValue(val) {
return (
typeof Buffer !== 'undefined' && val instanceof Buffer
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wrap this line to () brackets

|| val instanceof Date
|| val instanceof RegExp
) ? true : false;
}

args.forEach(function (obj) {
// skip argument if it is array or isn't object
if (typeof obj !== 'object' || Array.isArray(obj)) {
return;
function cloneSpecificValue(val) {
if (typeof Buffer !== 'undefined' && val instanceof Buffer) {
var x = new Buffer(val.length);
val.copy(x);
return x;
} else if (val instanceof Date) {
return new Date(val.getTime());
} else if (val instanceof RegExp) {
return new RegExp(val);
} else {
throw new Error('Unexpected situation');
}
}

Object.keys(obj).forEach(function (key) {
src = target[key]; // source value
val = obj[key]; // new value
/**
* Recursive cloning array.
*/
function deepCloneArray(arr) {
var clone = [];
arr.forEach(function (item, index) {
if (typeof item === 'object' && item !== null) {
if (Array.isArray(item)) {
clone[index] = deepCloneArray(item);
} else if (isSpecificValue(item)) {
clone[index] = cloneSpecificValue(item);
} else {
clone[index] = deepExtend({}, item);
}
} else {
clone[index] = item;
}
});
return clone;
}

// recursion prevention
if (val === target) {
return;
/**
* Extening object that entered in first argument.
*
* Returns extended object or false if have no target object or incorrect type.
*
* If you wish to clone source object (without modify it), just use empty new
* object as first argument, like this:
* deepExtend({}, yourObj_1, [yourObj_N]);
*/
var deepExtend = function (/*obj_1, [obj_2], [obj_N]*/) {
if (arguments.length < 1 || typeof arguments[0] !== 'object') {
return false;
}

/**
* if new value isn't object then just overwrite by new value
* instead of extending.
*/
} else if (typeof val !== 'object' || val === null) {
target[key] = val;
return;
if (arguments.length < 2) {
return arguments[0];
}

// just clone arrays (and recursive clone objects inside)
} else if (Array.isArray(val)) {
target[key] = deepCloneArray(val);
return;
var target = arguments[0];

// custom cloning and overwrite for specific objects
} else if (isSpecificValue(val)) {
target[key] = cloneSpecificValue(val);
return;
// convert arguments to array and cut off target object
var args = Array.prototype.slice.call(arguments, 1);

// overwrite by new value if source isn't object or array
} else if (typeof src !== 'object' || src === null || Array.isArray(src)) {
target[key] = deepExtend({}, val);
return;
var val, src, clone;

// source value and new value is objects both, extending...
} else {
target[key] = deepExtend(src, val);
args.forEach(function (obj) {
// skip argument if it is array or isn't object
if (typeof obj !== 'object' || Array.isArray(obj)) {
return;
}

Object.keys(obj).forEach(function (key) {
src = target[key]; // source value
val = obj[key]; // new value

// recursion prevention
if (val === target) {
return;

/**
* if new value isn't object then just overwrite by new value
* instead of extending.
*/
} else if (typeof val !== 'object' || val === null) {
target[key] = val;
return;

// just clone arrays (and recursive clone objects inside)
} else if (Array.isArray(val)) {
target[key] = deepCloneArray(val);
return;

// custom cloning and overwrite for specific objects
} else if (isSpecificValue(val)) {
target[key] = cloneSpecificValue(val);
return;

// overwrite by new value if source isn't object or array
} else if (typeof src !== 'object' || src === null || Array.isArray(src)) {
target[key] = deepExtend({}, val);
return;

// source value and new value is objects both, extending...
} else {
target[key] = deepExtend(src, val);
return;
}
});
});
});

return target;
}
return target;
}

return deepExtend;


Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove empty lines here

});