1 | 'use strict';
|
---|
2 |
|
---|
3 | /* eslint no-invalid-this: 1 */
|
---|
4 |
|
---|
5 | var ERROR_MESSAGE = 'Function.prototype.bind called on incompatible ';
|
---|
6 | var toStr = Object.prototype.toString;
|
---|
7 | var max = Math.max;
|
---|
8 | var funcType = '[object Function]';
|
---|
9 |
|
---|
10 | var 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 |
|
---|
23 | var 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 |
|
---|
31 | var 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 |
|
---|
42 | module.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 | };
|
---|