proto.js 5.0 KB

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