Skip to content

Commit

Permalink
[New] return the native bind when available.
Browse files Browse the repository at this point in the history
  • Loading branch information
ljharb committed Feb 14, 2016
1 parent a3dd767 commit 82186e0
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 53 deletions.
48 changes: 48 additions & 0 deletions implementation.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
var ERROR_MESSAGE = 'Function.prototype.bind called on incompatible ';
var slice = Array.prototype.slice;
var toStr = Object.prototype.toString;
var funcType = '[object Function]';

module.exports = function bind(that) {
var target = this;
if (typeof target !== 'function' || toStr.call(target) !== funcType) {
throw new TypeError(ERROR_MESSAGE + target);
}
var args = slice.call(arguments, 1);

var bound;
var binder = function () {
if (this instanceof bound) {
var result = target.apply(
this,
args.concat(slice.call(arguments))
);
if (Object(result) === result) {
return result;
}
return this;
} else {
return target.apply(
that,
args.concat(slice.call(arguments))
);
}
};

var boundLength = Math.max(0, target.length - args.length);
var boundArgs = [];
for (var i = 0; i < boundLength; i++) {
boundArgs.push('$' + i);
}

bound = Function('binder', 'return function (' + boundArgs.join(',') + '){ return binder.apply(this,arguments); }')(binder);

if (target.prototype) {
var Empty = function Empty() {};
Empty.prototype = target.prototype;
bound.prototype = new Empty();
Empty.prototype = null;
}

return bound;
};
50 changes: 2 additions & 48 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,49 +1,3 @@
var ERROR_MESSAGE = 'Function.prototype.bind called on incompatible ';
var slice = Array.prototype.slice;
var toStr = Object.prototype.toString;
var funcType = '[object Function]';

module.exports = function bind(that) {
var target = this;
if (typeof target !== 'function' || toStr.call(target) !== funcType) {
throw new TypeError(ERROR_MESSAGE + target);
}
var args = slice.call(arguments, 1);

var bound;
var binder = function () {
if (this instanceof bound) {
var result = target.apply(
this,
args.concat(slice.call(arguments))
);
if (Object(result) === result) {
return result;
}
return this;
} else {
return target.apply(
that,
args.concat(slice.call(arguments))
);
}
};

var boundLength = Math.max(0, target.length - args.length);
var boundArgs = [];
for (var i = 0; i < boundLength; i++) {
boundArgs.push('$' + i);
}

bound = Function('binder', 'return function (' + boundArgs.join(',') + '){ return binder.apply(this,arguments); }')(binder);

if (target.prototype) {
var Empty = function Empty() {};
Empty.prototype = target.prototype;
bound.prototype = new Empty();
Empty.prototype = null;
}

return bound;
};
var implementation = require('./implementation');

module.exports = Function.prototype.bind || implementation;
7 changes: 2 additions & 5 deletions test/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
var test = require('tape');

var functionBind = require('../index');
var functionBind = require('../implementation');
var getCurrentContext = function () { return this; };

test('functionBind is a function', function (t) {
Expand All @@ -9,13 +9,11 @@ test('functionBind is a function', function (t) {
});

test('non-functions', function (t) {
var errorPrefix = 'Function.prototype.bind called on incompatible ';
var nonFunctions = [true, false, [], {}, 42, 'foo', NaN, /a/g];
t.plan(nonFunctions.length * 2);
t.plan(nonFunctions.length);
for (var i = 0; i < nonFunctions.length; ++i) {
try { functionBind.call(nonFunctions[i]); } catch (ex) {
t.ok(ex instanceof TypeError, 'throws when given ' + String(nonFunctions[i]));
t.equal(ex.message, errorPrefix + String(nonFunctions[i]), 'exception message is correct for ' + nonFunctions[i]);
}
}
t.end();
Expand Down Expand Up @@ -250,4 +248,3 @@ test('bound function length', function (t) {
st.end();
});
});

0 comments on commit 82186e0

Please sign in to comment.