|
108 | 108 | }; |
109 | 109 | }; |
110 | 110 |
|
| 111 | + // An internal function for creating a new object that inherits from another. |
| 112 | + var baseCreate = function(prototype) { |
| 113 | + if (!_.isObject(prototype)) return {}; |
| 114 | + if (nativeCreate) return nativeCreate(prototype); |
| 115 | + Ctor.prototype = prototype; |
| 116 | + var result = new Ctor; |
| 117 | + Ctor.prototype = null; |
| 118 | + return result; |
| 119 | + }; |
| 120 | + |
111 | 121 | // Helper for collection methods to determine whether a collection |
112 | 122 | // should be iterated as an array or as an object |
113 | 123 | // Related: http://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength |
|
674 | 684 | // Function (ahem) Functions |
675 | 685 | // ------------------ |
676 | 686 |
|
| 687 | + // Determines whether to execute a function as a constructor |
| 688 | + // or a normal function with the provided arguments |
| 689 | + var executeBound = function(sourceFunc, boundFunc, context, callingContext, args) { |
| 690 | + if (!(callingContext instanceof boundFunc)) return sourceFunc.apply(context, args); |
| 691 | + var self = baseCreate(sourceFunc.prototype); |
| 692 | + var result = sourceFunc.apply(self, args); |
| 693 | + if (_.isObject(result)) return result; |
| 694 | + return self; |
| 695 | + }; |
| 696 | + |
677 | 697 | // Create a function bound to a given object (assigning `this`, and arguments, |
678 | 698 | // optionally). Delegates to **ECMAScript 5**'s native `Function.bind` if |
679 | 699 | // available. |
680 | 700 | _.bind = function(func, context) { |
681 | 701 | if (nativeBind && func.bind === nativeBind) return nativeBind.apply(func, slice.call(arguments, 1)); |
682 | 702 | if (!_.isFunction(func)) throw new TypeError('Bind must be called on a function'); |
683 | 703 | var args = slice.call(arguments, 2); |
684 | | - return function bound() { |
685 | | - return func.apply(context || this, args.concat(slice.call(arguments))); |
| 704 | + var bound = function() { |
| 705 | + return executeBound(func, bound, context, this, args.concat(slice.call(arguments))); |
686 | 706 | }; |
| 707 | + return bound; |
687 | 708 | }; |
688 | 709 |
|
689 | 710 | // Partially apply a function by creating a version that has had some of its |
690 | 711 | // arguments pre-filled, without changing its dynamic `this` context. _ acts |
691 | 712 | // as a placeholder, allowing any combination of arguments to be pre-filled. |
692 | 713 | _.partial = function(func) { |
693 | 714 | var boundArgs = slice.call(arguments, 1); |
694 | | - return function bound() { |
| 715 | + var bound = function() { |
695 | 716 | var position = 0, length = boundArgs.length; |
696 | 717 | var args = Array(length); |
697 | 718 | for (var i = 0; i < length; i++) { |
698 | 719 | args[i] = boundArgs[i] === _ ? arguments[position++] : boundArgs[i]; |
699 | 720 | } |
700 | 721 | while (position < arguments.length) args.push(arguments[position++]); |
701 | | - return func.apply(this, args); |
| 722 | + return executeBound(func, bound, this, this, args); |
702 | 723 | }; |
| 724 | + return bound; |
703 | 725 | }; |
704 | 726 |
|
705 | 727 | // Bind a number of an object's methods to that object. Remaining arguments |
|
0 commit comments