proto.es5.js 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. /*! uberproto - v1.2.0 - 2015-11-29
  2. * http://daffl.github.com/uberproto
  3. * Copyright (c) 2015 ; Licensed MIT */
  4. /**
  5. * A base object for ECMAScript 5 style prototypal inheritance.
  6. *
  7. * @see https://github.com/rauschma/proto-js/
  8. * @see http://ejohn.org/blog/simple-javascript-inheritance/
  9. * @see http://uxebu.com/blog/2011/02/23/object-based-inheritance-for-ecmascript-5/
  10. */
  11. (function (root, factory) {
  12. if (typeof define === 'function' && define.amd) {
  13. define([], factory);
  14. } else if (typeof exports === 'object') {
  15. module.exports = factory();
  16. } else {
  17. root.Proto = factory();
  18. }
  19. }(this, function () {
  20. function makeSuper(_super, old, name, fn) {
  21. return function () {
  22. var tmp = this._super;
  23. // Add a new ._super() method that is the same method
  24. // but either pointing to the prototype method
  25. // or to the overwritten method
  26. this._super = (typeof old === 'function') ? old : _super[name];
  27. // The method only need to be bound temporarily, so we
  28. // remove it when we're done executing
  29. var ret = fn.apply(this, arguments);
  30. this._super = tmp;
  31. return ret;
  32. };
  33. }
  34. function legacyMixin(prop, obj) {
  35. var self = obj || this;
  36. var fnTest = /\b_super\b/;
  37. var _super = Object.getPrototypeOf(self) || self.prototype;
  38. var _old;
  39. // Copy the properties over
  40. for (var name in prop) {
  41. // store the old function which would be overwritten
  42. _old = self[name];
  43. // Check if we're overwriting an existing function
  44. if(
  45. ((
  46. typeof prop[name] === 'function' &&
  47. typeof _super[name] === 'function'
  48. ) || (
  49. typeof _old === 'function' &&
  50. typeof prop[name] === 'function'
  51. )) && fnTest.test(prop[name])
  52. ) {
  53. self[name] = makeSuper(_super, _old, name, prop[name]);
  54. } else {
  55. self[name] = prop[name];
  56. }
  57. }
  58. return self;
  59. }
  60. function es5Mixin(prop, obj) {
  61. var self = obj || this;
  62. var fnTest = /\b_super\b/;
  63. var _super = Object.getPrototypeOf(self) || self.prototype;
  64. var descriptors = {};
  65. var proto = prop;
  66. var processProperty = function(name) {
  67. if(!descriptors[name]) {
  68. descriptors[name] = Object.getOwnPropertyDescriptor(proto, name);
  69. }
  70. };
  71. // Collect all property descriptors
  72. do {
  73. Object.getOwnPropertyNames(proto).forEach(processProperty);
  74. } while((proto = Object.getPrototypeOf(proto)) && Object.getPrototypeOf(proto));
  75. Object.keys(descriptors).forEach(function(name) {
  76. var descriptor = descriptors[name];
  77. if(typeof descriptor.value === 'function' && fnTest.test(descriptor.value)) {
  78. descriptor.value = makeSuper(_super, self[name], name, descriptor.value);
  79. }
  80. Object.defineProperty(self, name, descriptor);
  81. });
  82. return self;
  83. }
  84. return {
  85. /**
  86. * Create a new object using Object.create. The arguments will be
  87. * passed to the new instances init method or to a method name set in
  88. * __init.
  89. */
  90. create: function () {
  91. var instance = Object.create(this);
  92. var init = typeof instance.__init === 'string' ? instance.__init : 'init';
  93. if (typeof instance[init] === 'function') {
  94. instance[init].apply(instance, arguments);
  95. }
  96. return instance;
  97. },
  98. /**
  99. * Mixin a given set of properties
  100. * @param prop The properties to mix in
  101. * @param obj [optional] The object to add the mixin
  102. */
  103. mixin: typeof Object.defineProperty === 'function' ? es5Mixin : legacyMixin,
  104. /**
  105. * Extend the current or a given object with the given property
  106. * and return the extended object.
  107. * @param prop The properties to extend with
  108. * @param obj [optional] The object to extend from
  109. * @returns The extended object
  110. */
  111. extend: function (prop, obj) {
  112. return this.mixin(prop, Object.create(obj || this));
  113. },
  114. /**
  115. * Return a callback function with this set to the current or a given context object.
  116. * @param name Name of the method to proxy
  117. * @param args... [optional] Arguments to use for partial application
  118. */
  119. proxy: function (name) {
  120. var fn = this[name];
  121. var args = Array.prototype.slice.call(arguments, 1);
  122. args.unshift(this);
  123. return fn.bind.apply(fn, args);
  124. }
  125. };
  126. }));