extend.js 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. 'use strict';
  2. /*!
  3. * node.extend
  4. * Copyright 2011, John Resig
  5. * Dual licensed under the MIT or GPL Version 2 licenses.
  6. * http://jquery.org/license
  7. *
  8. * @fileoverview
  9. * Port of jQuery.extend that actually works on node.js
  10. */
  11. var is = require('is');
  12. var has = require('has');
  13. var defineProperty = Object.defineProperty;
  14. var gOPD = Object.getOwnPropertyDescriptor;
  15. // If name is '__proto__', and Object.defineProperty is available, define __proto__ as an own property on target
  16. var setProperty = function setP(target, name, value) {
  17. if (defineProperty && name === '__proto__') {
  18. defineProperty(target, name, {
  19. enumerable: true,
  20. configurable: true,
  21. value: value,
  22. writable: true
  23. });
  24. } else {
  25. target[name] = value;
  26. }
  27. };
  28. // Return undefined instead of __proto__ if '__proto__' is not an own property
  29. var getProperty = function getP(obj, name) {
  30. if (name === '__proto__') {
  31. if (!has(obj, name)) {
  32. return void 0;
  33. } else if (gOPD) {
  34. // In early versions of node, obj['__proto__'] is buggy when obj has
  35. // __proto__ as an own property. Object.getOwnPropertyDescriptor() works.
  36. return gOPD(obj, name).value;
  37. }
  38. }
  39. return obj[name];
  40. };
  41. module.exports = function extend() {
  42. var target = arguments[0] || {};
  43. var i = 1;
  44. var length = arguments.length;
  45. var deep = false;
  46. var options, name, src, copy, copyIsArray, clone;
  47. // Handle a deep copy situation
  48. if (typeof target === 'boolean') {
  49. deep = target;
  50. target = arguments[1] || {};
  51. // skip the boolean and the target
  52. i = 2;
  53. }
  54. // Handle case when target is a string or something (possible in deep copy)
  55. if (typeof target !== 'object' && !is.fn(target)) {
  56. target = {};
  57. }
  58. for (; i < length; i++) {
  59. // Only deal with non-null/undefined values
  60. options = arguments[i];
  61. if (options != null) {
  62. if (typeof options === 'string') {
  63. options = options.split('');
  64. }
  65. // Extend the base object
  66. for (name in options) {
  67. src = getProperty(target, name);
  68. copy = getProperty(options, name);
  69. // Prevent never-ending loop
  70. if (target === copy) {
  71. continue;
  72. }
  73. // Recurse if we're merging plain objects or arrays
  74. if (deep && copy && (is.hash(copy) || (copyIsArray = is.array(copy)))) {
  75. if (copyIsArray) {
  76. copyIsArray = false;
  77. clone = src && is.array(src) ? src : [];
  78. } else {
  79. clone = src && is.hash(src) ? src : {};
  80. }
  81. // Never move original objects, clone them
  82. setProperty(target, name, extend(deep, clone, copy));
  83. // Don't bring in undefined values
  84. } else if (typeof copy !== 'undefined') {
  85. setProperty(target, name, copy);
  86. }
  87. }
  88. }
  89. }
  90. // Return the modified object
  91. return target;
  92. };