1'use strict'; 2 3/* eslint no-invalid-this: 1 */ 4 5var ERROR_MESSAGE = 'Function.prototype.bind called on incompatible '; 6var toStr = Object.prototype.toString; 7var max = Math.max; 8var funcType = '[object Function]'; 9 10var concatty = function concatty(a, b) { 11 var arr = []; 12 13 for (var i = 0; i < a.length; i += 1) { 14 arr[i] = a[i]; 15 } 16 for (var j = 0; j < b.length; j += 1) { 17 arr[j + a.length] = b[j]; 18 } 19 20 return arr; 21}; 22 23var slicy = function slicy(arrLike, offset) { 24 var arr = []; 25 for (var i = offset || 0, j = 0; i < arrLike.length; i += 1, j += 1) { 26 arr[j] = arrLike[i]; 27 } 28 return arr; 29}; 30 31var joiny = function (arr, joiner) { 32 var str = ''; 33 for (var i = 0; i < arr.length; i += 1) { 34 str += arr[i]; 35 if (i + 1 < arr.length) { 36 str += joiner; 37 } 38 } 39 return str; 40}; 41 42module.exports = function bind(that) { 43 var target = this; 44 if (typeof target !== 'function' || toStr.apply(target) !== funcType) { 45 throw new TypeError(ERROR_MESSAGE + target); 46 } 47 var args = slicy(arguments, 1); 48 49 var bound; 50 var binder = function () { 51 if (this instanceof bound) { 52 var result = target.apply( 53 this, 54 concatty(args, arguments) 55 ); 56 if (Object(result) === result) { 57 return result; 58 } 59 return this; 60 } 61 return target.apply( 62 that, 63 concatty(args, arguments) 64 ); 65 66 }; 67 68 var boundLength = max(0, target.length - args.length); 69 var boundArgs = []; 70 for (var i = 0; i < boundLength; i++) { 71 boundArgs[i] = '$' + i; 72 } 73 74 bound = Function('binder', 'return function (' + joiny(boundArgs, ',') + '){ return binder.apply(this,arguments); }')(binder); 75 76 if (target.prototype) { 77 var Empty = function Empty() {}; 78 Empty.prototype = target.prototype; 79 bound.prototype = new Empty(); 80 Empty.prototype = null; 81 } 82 83 return bound; 84}; 85