implementation.js 1.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253
  1. 'use strict';
  2. /* eslint no-invalid-this: 1 */
  3. var ERROR_MESSAGE = 'Function.prototype.bind called on incompatible ';
  4. var slice = Array.prototype.slice;
  5. var toStr = Object.prototype.toString;
  6. var funcType = '[object Function]';
  7. module.exports = function bind(that) {
  8. var target = this;
  9. if (typeof target !== 'function' || toStr.call(target) !== funcType) {
  10. throw new TypeError(ERROR_MESSAGE + target);
  11. }
  12. var args = slice.call(arguments, 1);
  13. var bound;
  14. var binder = function () {
  15. if (this instanceof bound) {
  16. var result = target.apply(
  17. this,
  18. args.concat(slice.call(arguments))
  19. );
  20. if (Object(result) === result) {
  21. return result;
  22. }
  23. return this;
  24. } else {
  25. return target.apply(
  26. that,
  27. args.concat(slice.call(arguments))
  28. );
  29. }
  30. };
  31. var boundLength = Math.max(0, target.length - args.length);
  32. var boundArgs = [];
  33. for (var i = 0; i < boundLength; i++) {
  34. boundArgs.push('$' + i);
  35. }
  36. bound = Function('binder', 'return function (' + boundArgs.join(',') + '){ return binder.apply(this,arguments); }')(binder);
  37. if (target.prototype) {
  38. var Empty = function Empty() {};
  39. Empty.prototype = target.prototype;
  40. bound.prototype = new Empty();
  41. Empty.prototype = null;
  42. }
  43. return bound;
  44. };