Niels B.
Niels B.

Reputation: 6310

Pass array of arguments without altering this

I'm trying to find the best way to pass an array of arguments to a function, but without altering (or addressing) the execution context.

I have this:

some_args = ["world"];
in.some.namespace.hello.apply(this, some_args);

Unfortunately this changes hellos execution context to the global object.

What's the slickest way of calling hello with in.some.namespace being the execution context?

Writing

in.some.namespace.hello.apply(in.some.namespace, some_args]

looks verbose and errorprone.

Upvotes: 3

Views: 73

Answers (3)

Gyum Fox
Gyum Fox

Reputation: 3627

If the question is simply to write the line of code as short as possible, consider caching in a variable what's redundant (it's also better for perfs as it reduces the number of lookups):

var n = in.some.namespace;
n.hello.apply(n, some_args);

Upvotes: 0

T.J. Crowder
T.J. Crowder

Reputation: 1075219

Writing

 in.some.namespace.hello.apply(in.some.namespace.hello, some_args]

looks verbose and errorprone.

(In the below I've changed in. to n. because you can't declare a variable called in and I wanted to provide some live examples.)

Three options, none of them really exciting: ;-)

  1. Use with, despite its bad rep and incompatibility with strict mode

  2. Write yourself a utility function

  3. Use a disposable variable and don't mind some really funky-looking syntax

Use with:

with (n.some) {
    namespace.hello.apply(namespace, some_args);
}

Slightly less repetition, though there's still some, and you have to use with, which is disallowed in strict mode.

Utility function

Example utility function:

function callWith(obj, name, args) {
  return obj[name].apply(obj, args);
}
var n = {
  some: {
    namespace: {
      hello: function(a, b, c) {
        alert(this.name + " says " + [a, b, c].join(", "));
      },
      name: "namespace"
    }
  }
};

callWith(n.some.namespace, "hello", [1, 2, 3]);

(Be careful doing that if you use a minifier that renames methods, as it probably won't update the string.)

Disposable variable and really funky syntax

I want to be clear that I'm not recommending this, just flagging it up as an option: If you have a variable you keep lying around for this purpose, you can do this:

(o = n.some.namespace, o.hello.apply(o, [1, 2, 3]));

E.g.:

var o;
var n = {
  some: {
    namespace: {
      hello: function(a, b, c) {
        alert(this.name + " says " + [a, b, c].join(", "));
      },
      name: "namespace"
    }
  }
};

(o = n.some.namespace, o.hello.apply(o, [1, 2, 3]));

Arguably that's an abusage of the comma operator. At the very least. :-)

Upvotes: 3

Gyum Fox
Gyum Fox

Reputation: 3627

If you are looking for a way to create a function delegate:

function $createDelegate(instance, method)
{
    return function (someArgs) { return method.apply(instance, someArgs); } 
}

Usage:

var delegate = $createDelegate(in.some.namespace, in.some.namespace.hello);
...
delegate(someArgs);

Which, for instance, is a very useful way to pass callbacks to an event Handler without loosing your context.

Upvotes: 0

Related Questions