| module.exports = extend; |
| |
| /* |
| var obj = {a: 3, b: 5}; |
| extend(obj, {a: 4, c: 8}); // {a: 4, b: 5, c: 8} |
| obj; // {a: 4, b: 5, c: 8} |
| |
| var obj = {a: 3, b: 5}; |
| extend({}, obj, {a: 4, c: 8}); // {a: 4, b: 5, c: 8} |
| obj; // {a: 3, b: 5} |
| |
| var arr = [1, 2, 3]; |
| var obj = {a: 3, b: 5}; |
| extend(obj, {c: arr}); // {a: 3, b: 5, c: [1, 2, 3]} |
| arr.push(4); |
| obj; // {a: 3, b: 5, c: [1, 2, 3, 4]} |
| |
| var arr = [1, 2, 3]; |
| var obj = {a: 3, b: 5}; |
| extend(true, obj, {c: arr}); // {a: 3, b: 5, c: [1, 2, 3]} |
| arr.push(4); |
| obj; // {a: 3, b: 5, c: [1, 2, 3]} |
| |
| extend({a: 4, b: 5}); // {a: 4, b: 5} |
| extend({a: 4, b: 5}, 3); {a: 4, b: 5} |
| extend({a: 4, b: 5}, true); {a: 4, b: 5} |
| extend('hello', {a: 4, b: 5}); // throws |
| extend(3, {a: 4, b: 5}); // throws |
| */ |
| |
| function extend(/* [deep], obj1, obj2, [objn] */) { |
| var args = [].slice.call(arguments); |
| var deep = false; |
| if (typeof args[0] == 'boolean') { |
| deep = args.shift(); |
| } |
| var result = args[0]; |
| if (isUnextendable(result)) { |
| throw new Error('extendee must be an object'); |
| } |
| var extenders = args.slice(1); |
| var len = extenders.length; |
| for (var i = 0; i < len; i++) { |
| var extender = extenders[i]; |
| for (var key in extender) { |
| if (Object.prototype.hasOwnProperty.call(extender, key)) { |
| var value = extender[key]; |
| if (deep && isCloneable(value)) { |
| var base = Array.isArray(value) ? [] : {}; |
| result[key] = extend( |
| true, |
| Object.prototype.hasOwnProperty.call(result, key) && !isUnextendable(result[key]) |
| ? result[key] |
| : base, |
| value |
| ); |
| } else { |
| result[key] = value; |
| } |
| } |
| } |
| } |
| return result; |
| } |
| |
| function isCloneable(obj) { |
| return Array.isArray(obj) || {}.toString.call(obj) == '[object Object]'; |
| } |
| |
| function isUnextendable(val) { |
| return !val || (typeof val != 'object' && typeof val != 'function'); |
| } |