4

Say I have two functions in JavaScript, and I want to pass the this pointer from one to the other. I know two ways to do this (shown below). Which one is the best practice?

Option 1:

function a() {
    b(this);
}

function b(elem) {
    alert(elem);
}

Option 2:

function a() {
    b.call(this);
}

function b() {
    alert(this);
}
smockle
  • 1,952
  • 15
  • 18
  • possible duplicate of [What is the difference between call and apply?](http://stackoverflow.com/questions/1986896/what-is-the-difference-between-call-and-apply) – andlrc Apr 11 '13 at 20:18
  • 2
    Your title doesn't match your question. – andlrc Apr 11 '13 at 20:20
  • How should I word the title? I'm willing to change it. (Assuming Stack Overflow allows me to; I've never edited a title before). – smockle Apr 11 '13 at 20:23
  • 1
    I changed the title to hopefully better reflect what I'm asking. Sorry for any inconvenience. – smockle Apr 11 '13 at 20:25
  • You are always allowed to edit your own posts. You need 2000 rep to edit someone else's posts without review from other users. I can see you already found out the first part :) I think you should accept Bergi's answer that it's the one trying to answer your question. – andlrc Apr 11 '13 at 20:30
  • Also you should see this question about `console.log` much better than `alert` for debugging: http://stackoverflow.com/questions/4743730/what-is-console-log-and-how-do-i-use-it – andlrc Apr 11 '13 at 20:31
  • @NULL Thanks! That's good to know. I appreciate your help. – smockle Apr 11 '13 at 20:33
  • 1
    There's also `bind` https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function/bind and jQuery's `$.proxy(this, ...)` – potench Apr 11 '13 at 20:40

3 Answers3

7

This doesn't answer the question, but the title to the question before it was changed:
What is the difference between function.call(this) and function(this) in JavaScript?


The use of call sets the context (this) of the called function:

function foo() {
    console.log(this);
}  

foo(); // window
foo.call({}); // {}

The default context using non strict mode (In a browser envirement) is window showed in the example above.

Non strict mode is the default mode. Strict mode is only supported by some browsers.

If the function is a method of an object the context is the object itself:

var obj = {
    foo: function () {
        console.log(this);
    }
};

obj.foo(); // obj
obj.foo.call({}); // {}

https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Operators/this

andlrc
  • 41,466
  • 13
  • 82
  • 108
2

There is really no best practice in general, just guidelines. It's strictly depends by the way you're coding. Personally, I would use the first form, it's more functional oriented rather than object oriented, and you avoid an additional operation – changing the contextual object – plus, you will not depends by the context object itself. It means, if you need to reuse b somewhere, you don't have all the time to change it's contextual object.

I'll give you a practical example. Let's say that b is a function that set the style.display of an element to none. Let's call it hide:

function hide(element) {
    element.style.display = "none";
}

You can use it like:

hide(document.getElementById("foo"))

So far so good. But what if you want to hide all elements of a list?

// this is used to have an array of element for the example,
// because NodeList are not Array
var slice = Function.call.bind(Array.prototype.slice);
var nodes = slice(document.getElementsByTagName("div"));

nodes.forEach(hide);

You simple have to pass hide. That's because the callback you pass to forEach, is called passing as first argument each value of the array.

But it's not over yet. Let's say you want to hide not all the div in the list, but only the div in the list that contains a the text "foo".

function hasFoo(element) {
    return element.textContent.indexOf("foo") > -1
}

Then:

nodes.filter(hasFoo).forEach(hide);

And so on. You can really takes advantages of the functional programming aspect and methods of JavaScript, if you decide to pass the "subject" of the function as first argument.

Here you can find the documentation of ES5 methods like filter and forEach.

ZER0
  • 22,173
  • 4
  • 45
  • 51
1

I know two ways to do this (shown below).

And as you see, both work :-)

Which one is the best practice?

It depends. Which does fit better in your code structure?

If you're coding very object-orientated and both functions are written in a neighborhood where you expect everything to be a method and the this keyword to reference an object instance everywhere, you should not break that.

If not, you should choose option #1 for simplicity. Also you might want to consider the other formal parameters b has - if the object reference doesn't go in a line with them, option #2 might be better.

Bergi
  • 513,640
  • 108
  • 821
  • 1,164
  • Thanks for the response! Could you elaborate on the last part please? What do you mean, "if the object reference doesn't go in a line with them"? – smockle Apr 11 '13 at 20:36