0
function sumArguments () {
  var value = this instanceof Number ? this : 0;
  for (var i = 0; i < arguments.length; i++) {
    value += arguments[i];
  }
  return value;
}

Function.prototype.apply1 = function() {
  var fn = this;
  var args = Array.prototype.slice.call(arguments);
  var context = args.shift();
  var newArgs = args[0];

  var boundfn = fn.bind(context, newArgs);

  return boundfn();
}

console.log(sumArguments.apply1(4, [1, 2, 3])); --> should equal 10

How can one implement apply without using apply? I'm getting stuck on how to transform the array of [1,2,3] to be passed in as 1,2,3 to bind.

3
  • 2
    "without using apply" Why? Commented Dec 19, 2015 at 0:49
  • Other than using eval() after constructing a string of code, it would likely require a native extension of the engine itself. The native Call() function and [[Call]] methods that define a function's ability to be invoked behave similarly to .apply(), accepting an argumentsList. Spreading the arguments is actually counter-productive. Commented Dec 19, 2015 at 0:51
  • You shouldn't use fn.bind because it returns new function with hard-coded context. While context is hard coded you can't invoke function with native apply or call. Commented Dec 19, 2015 at 1:13

3 Answers 3

1

Only way I could think of is using eval.

function apply(fn, args){
  var stringArgs = args.reduce(function(acc, el, i){
    var argString = 'args[' + i + ']';
    return acc += i === 0 ? argString : ',' + argString; 
  });
  return eval('fn(' + stringArgs + ')');
}
       
function test(first, second, third){
    console.log(first, second, third);
}

apply(test, [1, 2, 3]);

Although, I can't figure why would you need this. This also doesn't work with many data types like objects or strings. It does works for numbers though.

Edit: Now it works for any data type.

Sign up to request clarification or add additional context in comments.

Comments

1

Your goal here is to call fn.bind with the context and the provided arguments, right?

If you're using ES6, the spread operator ... is what you want:

foo(...[1,3,5]); //equivalent to foo(1, 3, 5)

fn.bind(context, ...args);

Otherwise, you can call apply on bind:

fn.bind.apply(fn, [context].concat(args));

Passing fn as the context of fn.bind will preserve its normal behavior, and you need to combine all of the arguments that you want to pass to bind into a single array, hence the concatenation.

Comments

0

Not sure why you'll need to use apply, but here's the sum function to give you what you want. It should be able to handle many inner arrays and ignore objects.

function sumArguments() {
    var value = this instanceof Number ? this : 0;
    for (var i = 0; i < arguments.length; i++) {
        if (typeof arguments[i] === 'number') {
            value += arguments[i];
        } else if (typeof arguments[i] === 'object' &&
                   typeof arguments[i].length !== 'undefined') {
            for (var j = 0; j < arguments[i].length; j++) {
                if (typeof arguments[i][j] === 'number') {
                    value += arguments[i][j];
                } else if (typeof arguments[i][j] === 'object' &&
                           typeof arguments[i][j].length !== 'undefined') {
                    value += sumArguments(arguments[i][j]);
                }
            }
        }
    }
    return value;
}

console.log(sumArguments(4, [1, 2, 3, [7, 8]], 5, 'a', 2));

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.