229

I thought this would be something I could easily google, but maybe I'm not asking the right question...

How do I set whatever "this" refers to in a given javascript function?

for example, like with most of jQuery's functions such as:

$(selector).each(function() {
   //$(this) gives me access to whatever selector we're on
});

How do I write/call my own standalone functions that have an appropriate "this" reference when called? I use jQuery, so if there's a jQuery-specific way of doing it, that'd be ideal.

Brian Tompsett - 汤莱恩
  • 5,195
  • 62
  • 50
  • 120
user126715
  • 3,350
  • 3
  • 20
  • 24

5 Answers5

322

Javascripts .call() and .apply() methods allow you to set the context for a function.

var myfunc = function(){
    alert(this.name);
};

var obj_a = {
    name:  "FOO"
};

var obj_b = {
    name:  "BAR!!"
};

Now you can call:

myfunc.call(obj_a);

Which would alert FOO. The other way around, passing obj_b would alert BAR!!. The difference between .call() and .apply() is that .call() takes a comma separated list if you're passing arguments to your function and .apply() needs an array.

myfunc.call(obj_a, 1, 2, 3);
myfunc.apply(obj_a, [1, 2, 3]);

Therefore, you can easily write a function hook by using the apply() method. For instance, we want to add a feature to jQuerys .css() method. We can store the original function reference, overwrite the function with custom code and call the stored function.

var _css = $.fn.css;
$.fn.css = function(){
   alert('hooked!');
   _css.apply(this, arguments);
};

Since the magic arguments object is an array like object, we can just pass it to apply(). That way we guarantee, that all parameters are passed through to the original function.

David Robles
  • 8,991
  • 8
  • 34
  • 45
jAndy
  • 212,463
  • 51
  • 293
  • 348
  • 6
    Just a fun tidbit: if you need to call the function repeatedly in reference to `obj_a`, for example, you can create a copy of it with `var boud_myfunc = myfunc.bind(obj_a)` and simply call `bound_myfunc()` as needed. – wbadart Nov 15 '16 at 07:20
47

Use function.call:

var f = function () { console.log(this); }
f.call(that, arg1, arg2, etc);

Where that is the object which you want this in the function to be.

palswim
  • 10,910
  • 6
  • 47
  • 72
  • 1
    `function` is a reserved keyword; consider updating your response to include a named function since `function.call(...)` is not valid JavaScript. – Daniel Allen Sep 14 '17 at 14:44
  • 1
    @DanielAllen: Without the definition of whatever sample function name I would provide, the code will still throw a JS error. But, I updated the sample function name. – palswim Sep 15 '17 at 01:00
21

Another basic example:

NOT working:

var img = new Image;
img.onload = function() {
   this.myGlobalFunction(img);
};
img.src = reader.result;

Working:

var img = new Image;
img.onload = function() {
   this.myGlobalFunction(img);
}.bind(this);
img.src = reader.result;

So basically: just add .bind(this) to your function

Joery
  • 561
  • 5
  • 5
  • 1
    This should be the accepted answer. Much easier syntax, much easier on the mind...good job Joery – nenea Apr 18 '19 at 02:37
18

You can use the bind function to set the context of this within a function.

function myFunc() {
  console.log(this.str)
}
const myContext = {str: "my context"}
const boundFunc = myFunc.bind(myContext);
boundFunc(); // "my context"
Scott Jungwirth
  • 4,702
  • 32
  • 32
17

jQuery uses a .call(...) method to assign the current node to this inside the function you pass as the parameter.

EDIT:

Don't be afraid to look inside jQuery's code when you have a doubt, it's all in clear and well documented Javascript.

ie: the answer to this question is around line 574,
callback.call( object[ name ], name, object[ name ] ) === false

Mic
  • 23,536
  • 8
  • 55
  • 69