"this" in JavaScript objects vs. jQuery $(this) - javascript

I've stumbled over a problem. I have an object method foo defined as:
var obj = {
foo: function() {
$('.personName').mouseover(function() {
this.highlight($(this).attr('faceIndex'));
});
}
}
So what should happen is that whenever the mouse cursor is over an HTML object of type personName, the obj.highlight method should be called with the faceIndex value from the HTML object as an argument. However I apparently have a clash between two this's: the one of jQuery and the one of JavaScript (referencing to obj from inside obj).
What can (should) I do? Have I violated some good programming practice?

A typical pattern to work around this is to use a local variable to store the first this:
var obj = {
foo: function() {
var _this = this;
$('.personName').mouseover(function() {
_this.highlight($(this).attr('faceIndex'));
});
}
}
Using a language like TypeScript or an ES6 compiler makes it easier to use this pattern without having to write the _this by hand each time.

Short answer: do
$('.personName').mouseover(function(event) {
obj.highlight($(event.target).attr('faceIndex'));
});
Longer explanation:
Javascript doesn't really have a concept of this. At least not in the way you're used to thinking of it. Oh there's a keyword alright, and it kind of does the thing you expect a lot of the times but it doesn't work the way that you probably think.
The fact of the matter is that in javascipt, this is no different than any other parameter. Let me show you.
Most people are aware that in javascript you can invoke functions like this doSomething(param1, param2) or like this doSomething.call(null, param1, param2). If you wanted, you can write all function invocations using .call
See that null there? Anything you pass in there is what this gets set to.
doSomething.call(null, param1, param2);
doSomething.call(obj, param1, param2);
doSomething.call(window, param1, param2);
doSomething.call("foobar", param1, param2);
If you don't use .call the runtime just takes a guess at what value you want there.
So given this, consider that the only difference between this and any other parameter is that you don't get to give this a name! Your problem is that you have two function scopes and the inner one has a variable named this which hides the outer one's this.
Solution: don't use this. Most libraries in fact (jquery included), don't force you to use this and also pass in the value as a regular parameter
$('.personName').mouseover(function(event) {
obj.highlight($(event.target).attr('faceIndex'));
});
ambiguity solved!
Avoid using this in JavaScript, if at all possible. It is almost never necessary.

this in javascript is a very difficult thing to understand in callbacks because it may refer to virtually any instance. And that is because the callback is called from a different context.
The long story : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this
As an alternative to previous answers :
One way I prefer dealing with it is by using a bind, also known as a proxy (in JQuery). jQuery has one implemented here : jQuery.proxy.
It has the benefit of letting you chose who is your this in the callback function.
For example:
var obj = {
foo: function() {
$('.personName').mouseover($.proxy(function(event) {
// this refers here to obj instance
console.log(this);
// event is a jQuery decorated that holds the reference of your element
console.log(event);
}, this));
}
};
And the true benefit of it, is that it lets you construct components that don't have "ugly" nested callback anonymous functions:
var obj = {
foo: function() {
$('.personName').mouseover($.proxy(this.mouseOverCallback, this));
},
mouseOverCallback : function(event) {
// this refers here to obj instance
console.log(this);
// event is a jQuery decorated that holds the reference of your element
console.log(event);
}
};

Related

JavaScript Proxy Pattern Explained

I study JavaScript Proxy Pattern, but I still do not get, where I can benefit from it. I would therefore like to provide you with two examples and kindly ask you to point at the difference between them.
Please, take a look at the code below:
What is the difference between the two addEventListener calls? One of them calls handleDrop in regular way. The other uses Proxy Pattern.
What will I gain using Proxy pattern approach?
I tested both functions, and they both call handleDrop successfully.
DndUpload.prototype.buildDropZone = function ()
{
var self = this,
this.dropZone.addEventListener('drop', function (e) { self.handleDrop.call(self, e) }, false);
this.dropZone.addEventListener('drop', self.handleDrop, false);
DndUpload.prototype.handleDrop = function (e)
{
alert("test");
...
};
}
You can provide me with good reference which contains very clear explanation of Proxy Pattern in JavaScript.
So what you're describing in your example isn't so much a demonstration of the Proxy pattern as much as a demonstration of confusion regarding the "calling object" and how it works in JavaScript.
In JavaScript, functions are "first-class." This essentially means that functions are data just like any other data. So let's consider the following situation:
var fn = (function () { return this.x; }),
a = {
x : 1,
fn : fn,
},
x = 2,
nothing = (function (z) { return z; });
So, we have an object a, which has two properties: fn and x. We also have variables x, fn (which is a function returning this.x), and nothing (which returns whatever it gets passed).
If we evaluate a.x, we get 1. If we evaluate x, we get 2. Pretty simple, eh? Now, if we evaluate nothing(a.x), then we get 1. That's also very simple. But it's important to realize that the value 1 associated with the property a.x is not in any way connected to the object a. It exists independently and can be passed around simply as a value.
In JavaScript, functions work the same way. Functions that are properties (often called "methods") can be passed as simple references. However, in doing so, they can become disconnected from their object. This becomes important when you use the this keyword inside a function.
The this keyword references the "calling object." That's the object that is associated with a function when that function is evaluated. There are three basic ways to set the calling object for a function:
If the function is called using the dot operator (e.g. a.fn()), the relevant object (in the example, a) is set as the calling object.
If the function is called using the function's call or apply properties, then you can explicitly set the calling object (we'll see why this is useful in a second).
If no calling object is set through method 1 or method 2, the global object is used (in a browser, this is typically called window).
So, back to our code. If we call a.fn(), it will evaluate as 1. That's expected because the this keyword in the function will be set to a due to the use of the dot operator. However, if we call simply fn(), it will return 2 because it is referencing the x property of the global object (meaning our global x is used).
Now, here's where things get tricky. What if you called: nothing(a.fn)()? You might be surprised that the result is 2. This is because passing a.fn into nothing() passes a reference to fn, but does not retain the calling object!
This is the same concept as what's going on in your coding example. If your function handleDrop were to use the this keyword, you would find it has a different value depending on which handler form you use. This is because in your second example, you're passing a reference to handleDrop, but as with our nothing(a.fn)() example, by the time it gets called, the calling object reference is lost.
So let's add something else to the puzzle:
var b = {
x : 3
};
You'll note that while b has an x property (and therefore satisfies the requirements for fn's use of this), it doesn't have a property referencing fn. So if we wanted to call the fn function with its this set to b, it might seem we need to add a new property to b. But instead we can use the aforementioned apply method on fn to explicitly set b as the calling object:
fn.apply(b); //is 3
This can be used to "permanently" bind a calling object to a function by creating a new function "wrapper." It's not really permanently binding, it's just creating a new function that calls the old function with the desired calling object. Such a tool is often written like so:
Function.prototype.bind = function (obj) {
var self = this;
return function() {
return self.apply(obj, arguments);
};
};
So after executing that code, we could do the following:
nothing(a.fn.bind(a))(); //is 1.
It's nothing tricky. In fact, the bind() property is built into ES5 and works pretty much like the simple code above. And our bind code is actually a really complicated way to do something that we can do more simply. Since a has fn as a property, we can use the dot operator to call it directly. We can skip all the confusing use of call and apply. We just need to make sure when the function gets called, it gets called using the dot operator. We can see how to do it above, but in practice, it's far simpler and more intuitive:
nothing(function () { return a.fn(); })(); //is 1
Once you have an understanding of how data references can be stored in closure scope, how functions are first-class objects, and how the calling object works, this all becomes very simple to understand and reasonably intuitive.
As for "proxies," those also exploit the same concepts to hook into functions. So, let's say that you wanted to count the number of times a.fn gets called. You can do that by inserting a proxy, like so (making use of some concepts from our bind code from above):
var numCalls = (function () {
var calls = 0, target = a.fn;
a.fn = (function () {
calls++;
return target.apply(a, arguments);
});
return (function () {
return calls;
});
}());
So now, whenever you call numCalls(), it will return the number of times a.fn() was called without actually modifying the functionality of a.fn! which is pretty cool. However, you must keep in mind that you did change the function referenced by a.fn, so looking way back to the beginning of our code, you'll notice that a.fn is no longer the same as fn and can't be used interchangeably anymore. But the reasons should now be pretty obvious!
I know that was basically a week of JavaScript education in a couple pages of text, but that's about as simple as it gets. Once you understand the concepts, the functionality, usefulness, and power of many JavaScript patterns become very simple to understand.
Hope that made things clearer!
UPDATE: Thanks to #pimvdb for pointing out my unnecessary use of [].slice.call(arguments, 0). I have removed it because it's, well, unnecessary.
Basically, passing self.handleDrop directly is functionally equivalent to passing the following function:
function() {
return self.handleDrop.apply(this, arguments);
}
because everything is passed through to the original function:
The this value
The arguments
The return value
With this in mind, compare your functions as follows:
function(e) { self.handleDrop.call(self, e) }
function() { return self.handleDrop.apply(this, arguments); }
The difference with your proxy way is:
It doesn't pass the return value through.
It doesn't pass all arguments through (only the first, e)
It doesn't pass the this value through, but uses a predefined one: self.
Now, the first two items don't make a difference here, because addEventListener doesn't care about the return value, and it also only passes one argument anyway.
But the third item is important: it sets a different this value in the function. By default, this is the element you bind the event to (it it set by the browser). Using the proxy way, you can set another this value.
Now, in your snippet it is not fully clear why you're setting a prototype function each time buildDropZone is called. Usually you define prototype functions only once. But when your handler handleDrop is called using the proxy way, this refers to the DndUpload instance, which is consistent with prototype functions in general.
Consider the code below:
function printThis() {
console.log(this);
}
var someObject = {
performTest : function() {
var self = this;
someOtherObject.higherOrderFunction(printThis);
someOtherObject.higherOrderFunction(function(){printThis.call(self)});
}
}
var someOtherObject = {
higherOrderFunction : function(f) {
f();
}
}
What will someOtherObject.higherOrderFunction(printThis) return?
How about someOtherObject.higherOrderFunction(function(){printThis.call(self)})
The answer to the first question depends on who and how you call someObject.performTest(). If I just call someObject.performTest() from a global context, it will probably print Window.
The second one will always print the someObject instance no matter what.
The closures or 'proxy pattern' as you call it comes in handy when you want to control exactly the execution context of a function.
Note: this in javascript does not behave like it does in other languages(in Java for example).

OO Javascript callbacks: Am I doing it right?

Background: I am building a webapp that makes use of JQuery and the Facebook Javascript API. Since some users don't like Facebook, I have also built a thunking layer that emulates the necessary identity APIs for users who prefer not to use Facebook. To keep things clean and avoid code duplication, I have organized my Javascript code into a few classes.
Both Facebook and JQuery APIs make extensive use of callbacks. Since all of my functions are bound into objects, I found that I am using the following pattern frequently:
var obj_ref = this;
some_jquery_function_that_takes_a_callback(/* various args */,
function() { obj_ref.my_callback_method(); });
For readability, the obj in obj_ref is actually the name of the class.
Is there some nifty Javascript magic that is simpler or clearer, or is this as good as it gets?
Update: Some good commentary so far in the answers. I should have added that my callback methods generally needs to refer to variables or functions bound to the class. If I don't need that, then the anonymous function wrapper is unnecessary.
Update2: I've selected a best answer, but you should carefully read all of the answers. Each provides some useful insight into possible solutions.
If you need your this to be your obj_ref and you can assume an update to date JavaScript (which sadly you probably can't), you could use bind to do away with the wrappers:
Creates a new function that, when called, itself calls this function in the context of the provided this value, with a given sequence of arguments preceding any provided when the new function was called.
Then you could bind your methods to your objects and this:
some_jquery_function_that_takes_a_callback(/* various args */,
function() { obj_ref.my_callback_method(); });
would be the same as:
// In some initialization pass...
obj_ref.my_callback_method = obj_ref.my_callback_method.bind(obj_ref);
// And later...
some_jquery_function_that_takes_a_callback(/* various args */,
obj_ref.my_callback_method);
Then this would be obj_ref when my_callback_method is called.
Alternatively, you could pull in Underscore.js and use its bind or bindAll. You could always grab just bind or bindAll out of Underscore.js if you didn't want the whole thing.
Or, since you have jQuery in play already, you could use $.proxy in place of the standard bind:
Takes a function and returns a new one that will always have a particular context.
So you could do it like this:
// In some initialization pass...
obj_ref.my_callback_method = $.proxy(obj_ref.my_callback_method.bind, obj_ref);
// And later...
some_jquery_function_that_takes_a_callback(/* various args */,
obj_ref.my_callback_method);
Thanks to dsfq for reminding me about jQuery's version of bind.
Better to use binding to the your object to preserve invocation context:
var objRef = this;
// #1. In this case you will have wrong context inside myCallbackMethod
// often it's not what you want. e.g. you won't be able to call another objRef methods
someJqueryFunction(a, b, objRef.myCallbackMethod);
// #2. Proper way - using proxy (bind) function
someJqueryFunction(a, b, $.proxy(objRef.myCallbackMethod, objRef));
I have the same problem with callbacks. Here's how I've dealt with it.
Just like dfsq said, $.proxy does the job for you. You don't need any extra library like underscore.
Underscore js has it's own bind function which is like the $.proxy.
Apply and call (the javascript methods that can be called on functions) work great.
Let's say I have a object :
var Dog = {
name : "Wolfy",
bark : function(){
console.debug(this.name," barks!");
}
}
var AnotherDog = {
name : "Fang"
}
Dog.bark.call(AnotherDog); //--> Fang barks!
Dog.bark(); //--> Wolfy barks!
When you write your "classes", you could use this pattern to handle the invocation of callbacks.
In case you're not sure what proxy or bind do, they do something similar to this:
var Dog = {
name : "Wolfy",
bark : function(){
console.debug(this.name," barks!");
}
}
Dog.bark = funciton(){
var scope = Dog;
return Dog.bark.apply(scope,arguments);
}
Rewrites the bark function by wrapping it in a new functions which returns the result of the original function, but forces a specific scope to be used.
I usually only wrap the callback in a function when I have to pass in extra parameters:
var x = 42;
jQuery_something({}, function(y, z) { obj_ref.callback(x, y, z) });
And that is because you don't control the arguments passed into the callback yourself. But this is only if you need a reference to some var in the scope. And in some cases this means you will have to create a closure to capture the var, e.g. in a loop.
But if that's not the case, then I just pass in a reference to the function directly:
jQuery_something({}, obj_ref.callback);
Even this should work fine, since the callback reference is in scope in this particular example (so no need to copy it to obj_ref first:
jQuery_something({}, this.callback);
Obviously, the last example is about as simple and clean as it gets: "the callback argument for the jQuery method is this object's method named 'callback'"
Yes, this is quite correct. You can have a helper function which implements the pattern though to save some code.

How to pass 'this' along with a function?

I want to delegate some function calls from one object to another:
objA.feature = objA.component.feature;
(Assuming feature is supposed to be a function both in objA and in its component)
But that clearly doesn't work, because the reference to this gets stripped from the function and ends up being a completely different object when it gets called (it actually is objA instead of objB.component).
You need to write something like this in order to get it to work:
objA.feature = function() {
objA.component.feature.apply(objA.component, arguments);
};
Is there a shorter (idiomatic) way to do that?
There's a function called "bind" on the Function prototype in newer runtimes:
var newFunc = someFunc.bind(somethingThatShouldBeThis);
will make this refer to "somethingThatShouldBeThis" when "newFunc" is called.
You can steal code from something like the Functional library to provide a "bind" function in environments that lack a native one.
edit — here's the code from Functional:
Function.prototype.bind = function(object/*, args...*/) {
var fn = this;
var args = Array.slice(arguments, 1);
return function() {
return fn.apply(object, args.concat(Array.slice(arguments, 0)));
}
}
Pretty simple, eh? It just returns a function back to you that, when invoked, will call the first argument as a function, and also pass along whatever arguments you pass in to the result (that is, to "newFunc" in the example above). The main wrinkle is that this one also saves extra arguments passed in originally, which can sometimes be handy.
Here is a great article on scope:
Binding Scope in JavaScript
However, most JavaScript frameworks (MooTools, jQuery) have built in methods for this. jQuery uses "proxy" and MooTools uses "bind", so be sure to check the documentation of whatever framework you're using.
Your best bet is to use a createDelegate-style method like some of the frameworks do. A bare-bones implementation was posted on OdeToCode a few years ago.

How to access a method of a closure's parent object?

I have defined a class named MyClass and I have defined two methods myMethod1 and myMethod2 for it:
function MyClass() {}
MyClass.prototype.myMethod1 = function() {...};
MyClass.prototype.myMethod2 = function() {...};
Inside myMethod1, I use jQuery and there's a callback closure defined there:
MyClass.prototype.myMethod2 = function() {
$.jQuery({success: function(data) {
this.myMethod2();
}, ...});
}
Now the problem is that this no longer is referring to MyClass. The question is how can I refer to it? At the moment I have assigned it to a variable named thisObj and access it this way:
MyClass.prototype.myMethod2 = function() {
var thisObj = this;
$.jQuery({success: function(data) {
thisObj.myMethod2();
}, ...});
}
Is there a better way to access MyClass.this from the closure nested in myMethod2?
Thanks in advance.
The method you've used is often called the "that reference", because the name that is commonly used as a name for the copy of the this reference. See Crockford's talks on JavaScript for example.
Your solution is perfectly fine. Since you already have a closure there, may as well make use of it, that's absolutely fine.
But if you like, you can use jQuery.proxy instead, like this:
MyClass.prototype.myMethod2 = function() {
$.jQuery({success: jQuery.proxy(function(data) {
this.myMethod2();
}, this), ...});
}
Again, though, there's nothing wrong with your original solution. Using proxy can be helpful, though, when you want to reuse a function in lots of different places, or when you don't already have a closure and don't want to introduce one (perhaps because it would close over a lot of unrelated stuff). The good thing about proxy is that it creates a closure over a controlled set of stuff and not over the current scope.
You can pass a reference to this to the function, but your solution seems fine to me. You are just using the lexical scoping rules of Javascript so what is wrong?

var self = this?

Using instance methods as callbacks for event handlers changes the scope of this from "My instance" to "Whatever just called the callback". So my code looks like this
function MyObject() {
this.doSomething = function() {
...
}
var self = this
$('#foobar').bind('click', function(){
self.doSomethng()
// this.doSomething() would not work here
})
}
It works, but is that the best way to do it? It looks strange to me.
This question is not specific to jQuery, but specific to JavaScript in general. The core problem is how to "channel" a variable in embedded functions. This is the example:
var abc = 1; // we want to use this variable in embedded functions
function xyz(){
console.log(abc); // it is available here!
function qwe(){
console.log(abc); // it is available here too!
}
...
};
This technique relies on using a closure. But it doesn't work with this because this is a pseudo variable that may change from scope to scope dynamically:
// we want to use "this" variable in embedded functions
function xyz(){
// "this" is different here!
console.log(this); // not what we wanted!
function qwe(){
// "this" is different here too!
console.log(this); // not what we wanted!
}
...
};
What can we do? Assign it to some variable and use it through the alias:
var abc = this; // we want to use this variable in embedded functions
function xyz(){
// "this" is different here! --- but we don't care!
console.log(abc); // now it is the right object!
function qwe(){
// "this" is different here too! --- but we don't care!
console.log(abc); // it is the right object here too!
}
...
};
this is not unique in this respect: arguments is the other pseudo variable that should be treated the same way — by aliasing.
Yeah, this appears to be a common standard. Some coders use self, others use me. It's used as a reference back to the "real" object as opposed to the event.
It's something that took me a little while to really get, it does look odd at first.
I usually do this right at the top of my object (excuse my demo code - it's more conceptual than anything else and isn't a lesson on excellent coding technique):
function MyObject(){
var me = this;
//Events
Click = onClick; //Allows user to override onClick event with their own
//Event Handlers
onClick = function(args){
me.MyProperty = args; //Reference me, referencing this refers to onClick
...
//Do other stuff
}
}
If you are doing ES2015 or doing type script and ES5 then you can use arrow functions in your code and you don't face that error and this refers to your desired scope in your instance.
this.name = 'test'
myObject.doSomething(data => {
console.log(this.name) // this should print out 'test'
});
As an explanation: In ES2015 arrow functions capture this from their defining scope. Normal function definitions don't do that.
var functionX = function() {
var self = this;
var functionY = function(y) {
// If we call "this" in here, we get a reference to functionY,
// but if we call "self" (defined earlier), we get a reference to function X.
}
}
edit: in spite of, nested functions within an object takes on the global window object rather than the surrounding object.
One solution to this is to bind all your callback to your object with javascript's bind method.
You can do this with a named method,
function MyNamedMethod() {
// You can now call methods on "this" here
}
doCallBack(MyNamedMethod.bind(this));
Or with an anonymous callback
doCallBack(function () {
// You can now call methods on "this" here
}.bind(this));
Doing these instead of resorting to var self = this shows you understand how the binding of this behaves in javascript and doesn't rely on a closure reference.
Also, the fat arrow operator in ES6 basically is the same a calling .bind(this) on an anonymous function:
doCallback( () => {
// You can reference "this" here now
});
I haven't used jQuery, but in a library like Prototype you can bind functions to a specific scope. So with that in mind your code would look like this:
$('#foobar').ready('click', this.doSomething.bind(this));
The bind method returns a new function that calls the original method with the scope you have specified.
Just adding to this that in ES6 because of arrow functions you shouldn't need to do this because they capture the this value.
I think it actually depends on what are you going to do inside your doSomething function. If you are going to access MyObject properties using this keyword then you have to use that. But I think that the following code fragment will also work if you are not doing any special things using object(MyObject) properties.
function doSomething(){
.........
}
$("#foobar").ready('click', function(){
});

Categories