index.js (3321B)
1 'use strict'; 2 3 var hasOwn = Object.prototype.hasOwnProperty; 4 var toStr = Object.prototype.toString; 5 var defineProperty = Object.defineProperty; 6 var gOPD = Object.getOwnPropertyDescriptor; 7 8 var isArray = function isArray(arr) { 9 if (typeof Array.isArray === 'function') { 10 return Array.isArray(arr); 11 } 12 13 return toStr.call(arr) === '[object Array]'; 14 }; 15 16 var isPlainObject = function isPlainObject(obj) { 17 if (!obj || toStr.call(obj) !== '[object Object]') { 18 return false; 19 } 20 21 var hasOwnConstructor = hasOwn.call(obj, 'constructor'); 22 var hasIsPrototypeOf = obj.constructor && obj.constructor.prototype && hasOwn.call(obj.constructor.prototype, 'isPrototypeOf'); 23 // Not own constructor property must be Object 24 if (obj.constructor && !hasOwnConstructor && !hasIsPrototypeOf) { 25 return false; 26 } 27 28 // Own properties are enumerated firstly, so to speed up, 29 // if last one is own, then all properties are own. 30 var key; 31 for (key in obj) { /**/ } 32 33 return typeof key === 'undefined' || hasOwn.call(obj, key); 34 }; 35 36 // If name is '__proto__', and Object.defineProperty is available, define __proto__ as an own property on target 37 var setProperty = function setProperty(target, options) { 38 if (defineProperty && options.name === '__proto__') { 39 defineProperty(target, options.name, { 40 enumerable: true, 41 configurable: true, 42 value: options.newValue, 43 writable: true 44 }); 45 } else { 46 target[options.name] = options.newValue; 47 } 48 }; 49 50 // Return undefined instead of __proto__ if '__proto__' is not an own property 51 var getProperty = function getProperty(obj, name) { 52 if (name === '__proto__') { 53 if (!hasOwn.call(obj, name)) { 54 return void 0; 55 } else if (gOPD) { 56 // In early versions of node, obj['__proto__'] is buggy when obj has 57 // __proto__ as an own property. Object.getOwnPropertyDescriptor() works. 58 return gOPD(obj, name).value; 59 } 60 } 61 62 return obj[name]; 63 }; 64 65 module.exports = function extend() { 66 var options, name, src, copy, copyIsArray, clone; 67 var target = arguments[0]; 68 var i = 1; 69 var length = arguments.length; 70 var deep = false; 71 72 // Handle a deep copy situation 73 if (typeof target === 'boolean') { 74 deep = target; 75 target = arguments[1] || {}; 76 // skip the boolean and the target 77 i = 2; 78 } 79 if (target == null || (typeof target !== 'object' && typeof target !== 'function')) { 80 target = {}; 81 } 82 83 for (; i < length; ++i) { 84 options = arguments[i]; 85 // Only deal with non-null/undefined values 86 if (options != null) { 87 // Extend the base object 88 for (name in options) { 89 src = getProperty(target, name); 90 copy = getProperty(options, name); 91 92 // Prevent never-ending loop 93 if (target !== copy) { 94 // Recurse if we're merging plain objects or arrays 95 if (deep && copy && (isPlainObject(copy) || (copyIsArray = isArray(copy)))) { 96 if (copyIsArray) { 97 copyIsArray = false; 98 clone = src && isArray(src) ? src : []; 99 } else { 100 clone = src && isPlainObject(src) ? src : {}; 101 } 102 103 // Never move original objects, clone them 104 setProperty(target, { name: name, newValue: extend(deep, clone, copy) }); 105 106 // Don't bring in undefined values 107 } else if (typeof copy !== 'undefined') { 108 setProperty(target, { name: name, newValue: copy }); 109 } 110 } 111 } 112 } 113 } 114 115 // Return the modified object 116 return target; 117 };