index.js 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. /*!
  2. * static-extend <https://github.com/jonschlinkert/static-extend>
  3. *
  4. * Copyright (c) 2016, Jon Schlinkert.
  5. * Licensed under the MIT License.
  6. */
  7. 'use strict';
  8. var copy = require('object-copy');
  9. var define = require('define-property');
  10. var util = require('util');
  11. /**
  12. * Returns a function for extending the static properties,
  13. * prototype properties, and descriptors from the `Parent`
  14. * constructor onto `Child` constructors.
  15. *
  16. * ```js
  17. * var extend = require('static-extend');
  18. * Parent.extend = extend(Parent);
  19. *
  20. * // optionally pass a custom merge function as the second arg
  21. * Parent.extend = extend(Parent, function(Child) {
  22. * Child.prototype.mixin = function(key, val) {
  23. * Child.prototype[key] = val;
  24. * };
  25. * });
  26. *
  27. * // extend "child" constructors
  28. * Parent.extend(Child);
  29. *
  30. * // optionally define prototype methods as the second arg
  31. * Parent.extend(Child, {
  32. * foo: function() {},
  33. * bar: function() {}
  34. * });
  35. * ```
  36. * @param {Function} `Parent` Parent ctor
  37. * @param {Function} `extendFn` Optional extend function for handling any necessary custom merging. Useful when updating methods that require a specific prototype.
  38. * @param {Function} `Child` Child ctor
  39. * @param {Object} `proto` Optionally pass additional prototype properties to inherit.
  40. * @return {Object}
  41. * @api public
  42. */
  43. function extend(Parent, extendFn) {
  44. if (typeof Parent !== 'function') {
  45. throw new TypeError('expected Parent to be a function.');
  46. }
  47. return function(Ctor, proto) {
  48. if (typeof Ctor !== 'function') {
  49. throw new TypeError('expected Ctor to be a function.');
  50. }
  51. util.inherits(Ctor, Parent);
  52. copy(Ctor, Parent);
  53. // proto can be null or a plain object
  54. if (typeof proto === 'object') {
  55. var obj = Object.create(proto);
  56. for (var k in obj) {
  57. Ctor.prototype[k] = obj[k];
  58. }
  59. }
  60. // keep a reference to the parent prototype
  61. define(Ctor.prototype, '_parent_', {
  62. configurable: true,
  63. set: function() {},
  64. get: function() {
  65. return Parent.prototype;
  66. }
  67. });
  68. if (typeof extendFn === 'function') {
  69. extendFn(Ctor, Parent);
  70. }
  71. Ctor.extend = extend(Ctor, extendFn);
  72. };
  73. };
  74. /**
  75. * Expose `extend`
  76. */
  77. module.exports = extend;