lodash: Add native method overwrite detection and optimize bind for native bind. [jddalton]

Former-commit-id: d968957e494fb828df155d2f9b0d3faf24e38b5e
This commit is contained in:
John-David Dalton
2012-05-06 17:55:23 -04:00
parent 6d3d5f77bc
commit 14c8863657
3 changed files with 59 additions and 9 deletions

View File

@@ -29,6 +29,9 @@
/** Used to restore the original `_` reference in `noConflict` */
var oldDash = window._;
/** Used to detect if a method is native */
var reNative = /\{\s*\[native code\]\s*\}/;
/** Used to match tokens in template text */
var reToken = /__token__(\d+)/g;
@@ -65,10 +68,14 @@
slice = ArrayProto.slice,
toString = ObjectProto.toString;
/* Used if `Function#bind` exists and is inferred to be fast (i.e. all but V8) */
var nativeBind = reNative.test(nativeBind = slice.bind) &&
(/\n/.test(nativeBind) || toString.call(window.opera) == '[object Opera]') && nativeBind;
/* Native method shortcuts for methods with the same name as other `lodash` methods */
var nativeIsArray = Array.isArray,
var nativeIsArray = reNative.test(nativeIsArray = Array.isArray) && nativeIsArray,
nativeIsFinite = window.isFinite,
nativeKeys = Object.keys;
nativeKeys = reNative.test(nativeKeys = Object.keys) && nativeKeys;
/** Timer shortcuts */
var clearTimeout = window.clearTimeout,
@@ -1548,19 +1555,41 @@
* // => 'hi moe!'
*/
function bind(func, thisArg) {
var args = slice.call(arguments, 2),
argsLength = args.length,
var methodName,
isFunc = toString.call(func) == funcClass;
// juggle arguments
if (!isFunc) {
var methodName = thisArg;
methodName = thisArg;
thisArg = func;
}
// use native `Function#bind` if faster
else if (nativeBind) {
func = nativeBind.call.apply(nativeBind, arguments);
return function() {
return func.apply(undefined, arguments);
};
}
var partialArgs = slice.call(arguments, 2),
partialArgsLength = partialArgs.length;
return function() {
push.apply(args, arguments);
var result = (isFunc ? func : thisArg[methodName]).apply(thisArg, args);
args.length = argsLength;
var result,
args = arguments;
if (!isFunc) {
func = thisArg[methodName];
}
if (partialArgsLength) {
if (args.length) {
partialArgs.length = partialArgsLength;
push.apply(partialArgs, args);
}
args = partialArgs;
}
result = args.length ? func.apply(thisArg, args) : func.call(thisArg);
partialArgs.length = partialArgsLength;
return result;
};
}

View File

@@ -12,7 +12,20 @@
<h2 id="qunit-userAgent"></h2>
<ol id="qunit-tests"></ol>
<script src="../vendor/qunit/qunit/qunit.js"></script>
<script>var _2, _3, _ = 1;</script>
<script>
var _2,
_3 = Object.keys;
Object.keys = function() { return []; };
</script>
<script src="../lodash.js"></script>
<script>
var lodashBadKeys = _,
_ = 1;
Object.keys = _3;
_3 = void 0;
</script>
<script src="../lodash.js"></script>
<script src="../vendor/requirejs/require.js"></script>
<script>

View File

@@ -62,6 +62,14 @@
skipTest(1)
}
});
test('avoids overwritten native methods', function() {
if (window.lodashBadKeys) {
notDeepEqual(lodashBadKeys.keys({ 'a': 1 }), []);
} else {
skipTest(1);
}
});
}());
/*--------------------------------------------------------------------------*/