Skip to content

Commit c9ee1c4

Browse files
Make Function#bind as ES5-compliant as possible.
1 parent 460be46 commit c9ee1c4

File tree

2 files changed

+47
-3
lines changed

2 files changed

+47
-3
lines changed

src/prototype/lang/function.js

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -105,13 +105,27 @@ Object.extend(Function.prototype, (function() {
105105
*
106106
* (To curry without binding, see [[Function#curry]].)
107107
**/
108+
108109
function bind(context) {
109-
if (arguments.length < 2 && Object.isUndefined(arguments[0])) return this;
110+
if (arguments.length < 2 && Object.isUndefined(arguments[0]))
111+
return this;
112+
113+
if (!Object.isFunction(this))
114+
throw new TypeError("The object is not callable.");
115+
116+
var nop = function() {};
110117
var __method = this, args = slice.call(arguments, 1);
111-
return function() {
118+
119+
var bound = function() {
112120
var a = merge(args, arguments);
113-
return __method.apply(context, a);
121+
var c = this instanceof nop ? this : context || window;
122+
return __method.apply(c, a);
114123
}
124+
125+
nop.prototype = this.prototype;
126+
bound.prototype = new nop();
127+
128+
return bound;
115129
}
116130

117131
/** related to: Function#bind

test/unit/function_test.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,36 @@ new Test.Unit.Runner({
4444
methodWithArguments.bind({ hi: 'withBindArgs' }, 'arg1', 'arg2')());
4545
this.assertEqual('withBindArgsAndArgs,arg1,arg2,arg3,arg4',
4646
methodWithArguments.bind({ hi: 'withBindArgsAndArgs' }, 'arg1', 'arg2')('arg3', 'arg4'));
47+
48+
49+
// Ensure that bound functions ignore their `context` when used as
50+
// constructors. Taken from example at:
51+
// https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/bind
52+
function Point(x, y) {
53+
this.x = x;
54+
this.y = y;
55+
}
56+
57+
Point.prototype.toString = function() {
58+
return this.x + "," + this.y;
59+
};
60+
61+
var p = new Point(1, 2);
62+
p.toString(); // "1,2"
63+
64+
var emptyObj = {};
65+
var YAxisPoint = Point.bind(emptyObj, 0 /* x */);
66+
67+
var axisPoint = new YAxisPoint(5);
68+
axisPoint.toString(); // "0,5"
69+
70+
this.assertEqual("0,5", axisPoint.toString(),
71+
"bound constructor should ignore context and curry properly");
72+
73+
this.assert(axisPoint instanceof Point,
74+
"should be an instance of Point");
75+
this.assert(axisPoint instanceof YAxisPoint,
76+
"should be an instance of YAxisPoint");
4777
},
4878

4979
testFunctionCurry: function() {

0 commit comments

Comments
 (0)