|
645 | 645 | // Reusable constructor function for prototype setting. |
646 | 646 | var Ctor = function(){}; |
647 | 647 |
|
| 648 | + // Determines whether to execute a function as a constructor |
| 649 | + // or a normal function with the provided arguments |
| 650 | + var executeBound = function(sourceFunc, boundFunc, context, callingContext, args) { |
| 651 | + if (!(callingContext instanceof boundFunc)) return sourceFunc.apply(context, args); |
| 652 | + Ctor.prototype = sourceFunc.prototype; |
| 653 | + var self = new Ctor; |
| 654 | + Ctor.prototype = null; |
| 655 | + var result = sourceFunc.apply(self, args); |
| 656 | + if (_.isObject(result)) return result; |
| 657 | + return self; |
| 658 | + }; |
| 659 | + |
648 | 660 | // Create a function bound to a given object (assigning `this`, and arguments, |
649 | 661 | // optionally). Delegates to **ECMAScript 5**'s native `Function.bind` if |
650 | 662 | // available. |
651 | 663 | _.bind = function(func, context) { |
652 | | - var args, bound; |
653 | 664 | if (nativeBind && func.bind === nativeBind) return nativeBind.apply(func, slice.call(arguments, 1)); |
654 | | - if (!_.isFunction(func)) throw new TypeError('Bind must be called on a function'); |
655 | | - args = slice.call(arguments, 2); |
656 | | - bound = function() { |
657 | | - if (!(this instanceof bound)) return func.apply(context, args.concat(slice.call(arguments))); |
658 | | - Ctor.prototype = func.prototype; |
659 | | - var self = new Ctor; |
660 | | - Ctor.prototype = null; |
661 | | - var result = func.apply(self, args.concat(slice.call(arguments))); |
662 | | - if (_.isObject(result)) return result; |
663 | | - return self; |
| 665 | + if (!_.isFunction(func)) throw TypeError('Bind must be called on a function'); |
| 666 | + var args = slice.call(arguments, 2); |
| 667 | + return function bound() { |
| 668 | + return executeBound(func, bound, context, this, args.concat(slice.call(arguments))); |
664 | 669 | }; |
665 | | - return bound; |
666 | 670 | }; |
667 | 671 |
|
668 | 672 | // Partially apply a function by creating a version that has had some of its |
669 | 673 | // arguments pre-filled, without changing its dynamic `this` context. _ acts |
670 | 674 | // as a placeholder, allowing any combination of arguments to be pre-filled. |
671 | 675 | _.partial = function(func) { |
672 | 676 | var boundArgs = slice.call(arguments, 1); |
673 | | - return function() { |
| 677 | + return function bound() { |
674 | 678 | var position = 0; |
675 | 679 | var args = boundArgs.slice(); |
676 | 680 | for (var i = 0, length = args.length; i < length; i++) { |
677 | 681 | if (args[i] === _) args[i] = arguments[position++]; |
678 | 682 | } |
679 | 683 | while (position < arguments.length) args.push(arguments[position++]); |
680 | | - return func.apply(this, args); |
| 684 | + return executeBound(func, bound, this, this, args); |
681 | 685 | }; |
682 | 686 | }; |
683 | 687 |
|
|
0 commit comments