Last active
March 2, 2017 01:30
-
-
Save dysfunc/9701950 to your computer and use it in GitHub Desktop.
angular.extend - shallow + deep copy (supports merging of arrays and deduping)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Deep copy example: | |
* angular.extend(true, { hello: 'world', app: { id: '1234', groups: [{ id: 1},2,3,4,5] }, ids: [1,2,3] }, { app: { name: 'bond', groups: [6, 7, {hello:'world', test: [1,2,3,4, [12,34,45]]}, 9] }, ids: [4,5,6,3] }); | |
* => "{"hello":"world","app":{"id":"1234","groups":[{"id":1},2,3,4,5,6,7,{"hello":"world","test":[1,2,3,4,[12,34,45]]},9],"name":"bond"},"ids":[1,2,3,4,5,6,3]}" | |
* | |
* Deep copy and dedup arrays | |
* angular.extend(true, true, { hello: 'world', app: { id: '1234', groups: [{ id: 1},2,3,4,5] }, ids: [1,2,3] }, { app: { name: 'bond', groups: [6, 7, {hello:'world', test: [1,2,3,4, [12,34,45]]}, 9] }, ids: [4,5,6,3] }); | |
* => "{"hello":"world","app":{"id":"1234","groups":[{"id":1},2,3,4,5,6,7,{"hello":"world","test":[1,2,3,4,[12,34,45]]},9],"name":"bond"},"ids":[1,2,3,4,5,6]}" | |
* | |
* vs jQuery deep copy | |
* jQuery.extend(true, { hello: 'world', app: { id: '1234', groups: [{ id: 1},2,3,4,5] }, ids: [1,2,3] }, { app: { name: 'bond', groups: [6, 7, {hello:'world', test: [1,2,3,4, [12,34,45]]}, 9] }, ids: [4,5,6,3] }); | |
* => {"hello":"world","app":{"id":"1234","groups":[6,7,{"hello":"world","test":[1,2,3,4,[12,34,45]]},9,5],"name":"bond"},"ids":[4,5,6]}" | |
* | |
* Shallow copy: (same as everyone else) | |
* angular.extend({ hello: [1,2,3,4] },{ hello: [5,6,7,8] }) | |
* => "{"hello":[5,6,7,8]}" | |
*/ | |
/* | |
* Determine whether an Object is a plain object or not (created using "{}" or "new Object") | |
* @param {Object} obj Object we want to check | |
* @return {Boolean} True/False result | |
*/ | |
angular.isPlainObject = function(obj){ | |
return !(typeof(obj) !== 'object' || obj && obj.nodeType || obj !== null && obj === obj.window || obj && obj.constructor && !Object.prototype.hasOwnProperty.call(obj.constructor.prototype, 'isPrototypeOf')); | |
}; | |
/** | |
* Removes duplicates from an Array | |
* @param {Array} Array Array to dedup | |
* @return {Array} Array containing only unique values | |
*/ | |
angular.unique = function(array){ | |
var a = array.concat(); | |
for(var i = 0; i < a.length; ++i){ | |
for(var j = i + 1; j < a.length; ++j){ | |
if(a[i] === a[j]){ | |
a.splice(j--, 1); | |
} | |
} | |
} | |
return a; | |
}; | |
/** | |
* Merge the contents of two or more objects into the target object | |
* @param {Boolean} deep If true, the merge becomes recursive (optional) | |
* @param {Object} target The object receiving the new properties | |
* @param {Object} arguments One or more additional objects to merge with the first | |
* @return {Object} The target object with the new contents | |
* | |
* angular.extend(object, object2) // shallow copy | |
* angular.extend(true, object, object2) // deep copy | |
* angular.extend(true, true, object, object2) // deep copy + dedup arrays | |
*/ | |
angular.extend = function(target){ | |
var i = 1, | |
deep = false, | |
dedup = false; | |
if(typeof(target) === 'boolean'){ | |
deep = target; | |
target = arguments[1] || {}; | |
i++; | |
if(typeof(target) === 'boolean'){ | |
dedup = target; | |
target = arguments[2] || {}; | |
i++; | |
} | |
} | |
[].slice.call(arguments, i).forEach(function(obj){ | |
var src, copy, isArray, clone; | |
if(obj === target){ | |
return; | |
} | |
if(deep && obj instanceof Array){ | |
target = dedup ? angular.unique(target.concat(obj)) : target.concat(obj); | |
} | |
else{ | |
for(var key in obj){ | |
src = target[key]; | |
copy = obj[key]; | |
if(target === copy || src === copy){ | |
continue; | |
} | |
if((isArray = copy instanceof Array) || deep && copy && (angular.isPlainObject(copy))){ | |
if(isArray){ | |
clone = (src && src instanceof Array) ? src : []; | |
}else{ | |
clone = (src && angular.isPlainObject(src)) ? src : {}; | |
} | |
isArray = false; | |
if(dedup){ | |
target[key] = angular.extend(deep, dedup, clone, copy); | |
}else{ | |
target[key] = angular.extend(deep, clone, copy); | |
} | |
} | |
else if(copy !== undefined){ | |
target[key] = copy; | |
} | |
} | |
} | |
}); | |
return target; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment