Make _.bind follow ES5 spec so it will work with a common Backbone pattern. [closes #11]

Former-commit-id: 8d5e399ca9727a32604601f81fffd9134104c8f4
This commit is contained in:
John-David Dalton
2012-05-24 01:25:08 -04:00
parent baa37450cc
commit c62b24b024
2 changed files with 90 additions and 9 deletions

View File

@@ -472,6 +472,15 @@
return '\\' + escapes[match];
}
/**
* A no-operation function.
*
* @private
*/
function noop() {
// no operation performed
}
/**
* Used by `template()` to replace "escape" template delimiters with tokens.
*
@@ -1701,18 +1710,20 @@
}
// use if `Function#bind` is faster
else if (nativeBind) {
func = nativeBind.call.apply(nativeBind, arguments);
return function() {
return arguments.length ? func.apply(undefined, arguments) : func();
};
return nativeBind.call.apply(nativeBind, arguments);
}
// spec'd to throw a TypeError
// http://es5.github.com/#x15.3.4.5
else if (toString.call(func) != funcClass) {
throw new TypeError;
}
var partialArgs = slice.call(arguments, 2),
partialArgsLength = partialArgs.length;
return function() {
var result,
args = arguments;
function bound() {
var args = arguments,
thisBinding = thisArg;
if (!isFunc) {
func = thisArg[methodName];
@@ -1724,10 +1735,27 @@
}
args = partialArgs;
}
result = args.length ? func.apply(thisArg, args) : func.call(thisArg);
var isInstance = this instanceof bound;
if (isInstance) {
// get `func` instance if `bound` is invoked in a `new` expression
noop.prototype = func.prototype;
thisBinding = new noop;
}
var result = args.length ? func.apply(thisBinding, args) : func.call(thisBinding);
partialArgs.length = partialArgsLength;
if (isInstance) {
// mimic a constructor's `return` behavior
// http://es5.github.com/#x13.2.2
return objectTypes[typeof result] && result !== null
? result
: thisBinding
}
return result;
};
}
return bound;
}
/**

View File

@@ -55,6 +55,17 @@
'seventeen', 'eighteen', 'nineteen', 'twenty'
];
var ctor = function() { },
func = function(greeting) { return greeting + ': ' + this.name; };
var lodashBoundNormal = lodash.bind(func, { 'name': 'moe' }),
lodashBoundCtor = lodash.bind(ctor, { 'name': 'moe' }),
lodashBoundPartial = lodash.bind(func, { 'name': 'moe' }, 'hi');
var _boundNormal = _.bind(func, { 'name': 'moe' }),
_boundCtor = _.bind(ctor, { 'name': 'moe' }),
_boundPartial = _.bind(func, { 'name': 'moe' }, 'hi');
for (var index = 0; index < 20; index++) {
numbers[index] = index;
object['key' + index] = index;
@@ -108,6 +119,48 @@
/*--------------------------------------------------------------------------*/
suites.push(
Benchmark.Suite('bind call')
.add('Lo-Dash', function() {
lodash.bind(func, { 'name': 'moe' }, 'hi');
})
.add('Underscore', function() {
_.bind(func, { 'name': 'moe' }, 'hi');
})
);
suites.push(
Benchmark.Suite('bound normal')
.add('Lo-Dash', function() {
lodashBoundNormal();
})
.add('Underscore', function() {
_boundNormal();
})
);
suites.push(
Benchmark.Suite('bound partial')
.add('Lo-Dash', function() {
lodashBoundPartial();
})
.add('Underscore', function() {
_boundPartial();
})
);
suites.push(
Benchmark.Suite('bound constructor')
.add('Lo-Dash', function() {
new lodashBoundCtor();
})
.add('Underscore', function() {
new _boundCtor();
})
);
/*--------------------------------------------------------------------------*/
suites.push(
Benchmark.Suite('each array')
.add('Lo-Dash', function() {