extend.js 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. var getProto = Object.getPrototypeOf || function (obj) {
  2. /*jshint proto: true */
  3. return obj.__proto__;
  4. };
  5. var hasOwn = Object.prototype.hasOwnProperty;
  6. var fnToString = hasOwn.toString;
  7. var ObjectFunctionString = fnToString.call(Object);
  8. /**
  9. * 测试对象是否是纯粹的对象(通过 "{}" 或者 "new Object" 创建的)。
  10. */
  11. var isPlainObject = function(obj) {
  12. var proto, Ctor;
  13. // Detect obvious negatives
  14. // Use toString instead of jQuery.type to catch host objects
  15. if (!obj || toString.call(obj) !== "[object Object]") {
  16. return false;
  17. }
  18. proto = getProto(obj);
  19. // Objects with no prototype (e.g., `Object.create( null )`) are plain
  20. if (!proto) {
  21. return true;
  22. }
  23. // Objects with prototype are plain iff they were constructed by a global Object function
  24. Ctor = hasOwn.call(proto, "constructor") && proto.constructor;
  25. return typeof Ctor === "function" && fnToString.call(Ctor) === ObjectFunctionString;
  26. };
  27. var isFunction = function (val) {
  28. return (typeof val === 'function');
  29. }
  30. var extend = function () {
  31. var options, name, src, copy, copyIsArray, clone,
  32. target = arguments[0] || {},
  33. i = 1,
  34. length = arguments.length,
  35. deep = false;
  36. // Handle a deep copy situation
  37. if (typeof target === "boolean") {
  38. deep = target;
  39. // Skip the boolean and the target
  40. target = arguments[i] || {};
  41. i++;
  42. }
  43. // Handle case when target is a string or something (possible in deep copy)
  44. if (typeof target !== "object" && !isFunction(target)) {
  45. target = {};
  46. }
  47. // Extend jQuery itself if only one argument is passed
  48. if (i === length) {
  49. target = this;
  50. i--;
  51. }
  52. for (; i < length; i++) {
  53. // Only deal with non-null/undefined values
  54. if ((options = arguments[i]) != null) {
  55. // Extend the base object
  56. for (name in options) {
  57. src = target[name];
  58. copy = options[name];
  59. // Prevent never-ending loop
  60. if (target === copy) {
  61. continue;
  62. }
  63. // Recurse if we're merging plain objects or arrays
  64. if (deep && copy && (isPlainObject(copy) ||
  65. (copyIsArray = Array.isArray(copy)))) {
  66. if (copyIsArray) {
  67. copyIsArray = false;
  68. clone = src && Array.isArray(src) ? src : [];
  69. } else {
  70. clone = src && isPlainObject(src) ? src : {};
  71. }
  72. // Never move original objects, clone them
  73. target[name] = extend(deep, clone, copy);
  74. // Don't bring in undefined values
  75. } else if (copy !== undefined) {
  76. target[name] = copy;
  77. }
  78. }
  79. }
  80. }
  81. // Return the modified object
  82. return target;
  83. };
  84. module.exports = {
  85. extend: extend
  86. }