Object oriented design in javascript and 'this' pointer - javascript

I am creating a object in javascript like this
function myobject() {
this.myvar1 = 0;
this.myvar2 = 0;
}
myobject.prototype.a = function(){
this.myvar1 +=1;
$('#button').click(function () { // 'this' is undefined
alert(this.myvar1)
})
}
var mything = new myobject();
mything.a()
What is the proper way to pass the this pointer to an anonymous function?

For updated question:
The issue is that inside that event handler, this refers to the element you clicked on, rather than your myobject, so just keep a reference to it, like this:
myobject.prototype.a = function(){
this.myvar1 +=1;
var self = this;
$('#button').click(function () {
alert(self.myvar1)
});
}
You can test it out here.
For previous question:
What you have should work (exactly as you have it), you can test it here.

Adding the following code to the end of your snippet and running it correctly alerts '1':
mything.b();
alert(mything.myvar1);
What were you expecting? Perhaps you're incorrectly invoking mything.b() ?

To pass this to an inner function, "save" it to another variable.
myobject.prototype.a = function() {
var self = this;
self.myvar1 += 1;
$('#button').click(function () {
alert(self.myvar1);
});
}

What's happening here is that jQuery is hijacking the value of this in the anonymous function used as a handler for the click event. It's kind of confusing, but jQuery's behavior is to assign the DOM element that triggered the event to this. There are a couple ways to set the value of this explicitly (the "context") for the callback function:
Function.prototype.bind - Part of the ECMAScript 5 standard, just starting to be implemented in browsers. For legacy support, you can extract it from the Prototype library.
$.proxy - jQuery's crappy equivalent of Function.prototype.bind, which was introduced in jQuery 1.4.
I wrote a couple posts on my blog that explain these in more detail if you're interested:
Organizing JavaScript with Namespaces and Function Prototypes
Understanding jQuery 1.4's $.proxy() method
In both cases, since this will now be your object and not the triggering DOM element, you can get the triggering DOM element by inspecting the event object, which will be the second parameter to your callback function.

Others here have done a nice job explaining the issue and how to resolve without adding any dependencies, but personally I think this plugin is a better overall solution (if you don't mind the dependency):
http://markdalgleish.com/projects/eventralize/

Related

Javascript call function with “this” on event [duplicate]

I have created a 'control' using jQuery and used jQuery.extend to assist in making it as OO as possible.
During the initialisation of my control I wire up various click events like so
jQuery('#available input',
this.controlDiv).bind('click', this, this.availableCategoryClick);
Notice that I am pasing 'this' as the data argument in the bind method. I do this so that I can get at data attached to the control instance rather from the element that fires the click event.
This works perfectly, however i suspect there is a better way
Having used Prototype in the past, I remember a bind syntax that allowed you to control what the value of 'this' was in the event.
What is the jQuery way?
You can use jQuery.proxy() with anonymous function, just a little awkward that 'context' is the second parameter.
$("#button").click($.proxy(function () {
//use original 'this'
},this));
I like your way, in fact use a similar construction:
$('#available_input').bind('click', {self:this}, this.onClick);
and the first line of this.onClick:
var self = event.data.self;
I like this way because then you get both the element clicked (as this) and the "this" object as self without having to use closures.
jQuery has the jQuery.proxy method (available since 1.4).
Example:
var Foo = {
name: "foo",
test: function() {
alert(this.name)
}
}
$("#test").click($.proxy(Foo.test, Foo))
// "foo" alerted
I don't think jQuery has a built-in feature for that. But you could use a helper construct like the following:
Function.prototype.createDelegate = function(scope) {
var fn = this;
return function() {
// Forward to the original function using 'scope' as 'this'.
return fn.apply(scope, arguments);
}
}
// Then:
$(...).bind(..., obj.method.createDelegate(obj));
This way, you can create dynamic 'wrapper functions' with createDelegate() that call the method with a given object as its 'this' scope.
Example:
function foo() {
alert(this);
}
var myfoo = foo.createDelegate("foobar");
myfoo(); // calls foo() with this = "foobar"
HTML 5-compliant browsers provide a bind method on Function.prototype which is, probably the cleanest syntax and is not framework-dependent, though it is not built into IE until IE 9. (There is a polyfill for browsers without it, though.)
Based on your example, you can use it like this:
jQuery('#available input',
this.controlDiv).bind('click', this.availableCategoryClick.bind(this));
(side note: the first bind in this statement is part of jQuery and has nothing to do with Function.prototype.bind)
Or to use slightly more concise and up-to-date jQuery (and eliminate confusion from two different kinds of binds):
$('#available input', this.controlDiv).click(this.availableCategoryClick.bind(this));
you can use the javascript bind method like this:
var coolFunction = function(){
// here whatever involving this
alert(this.coolValue);
}
var object = {coolValue: "bla"};
$("#bla").bind('click', coolFunction.bind(object));
jQuery does not support binds and the preferred way is to use functions.
Because in Javascript, this.availableCategoryClick does not mean calling the availableCategoryClick function on this object, jQuery advise to use this preferred syntax:
var self = this;
jQuery('#available input', self.controlDiv).bind('click', function(event)
{
self.availableCategoryClick(event);
});
OO concepts in Javascript are hard to understand, functionnal programming is often easier and more readable.
Seeing that functions changes scope, the most common way is to do it by hand, with something like var self = this.
var self = this
$('.some_selector').each(function(){
// refer to 'self' here
}

Javascript scope basics : .bind or self =this?

For me the below code do the same thing but I'm not totally sure so I would like to be sure:
var self = this;
this.param = 5;
var listener = sub.on('change', function() {
self.param = 10;
});
Is it identical to ?:
this.param = 5;
var listener = sub.on('change', function() {
this.param = 10;
}.bind(this));
They're not identical, but for your purposes in the example you posted they're close enough in that you get the same effect. The goal is to have a reference to the value of this outside the event handler later when the handler is actually invoked. Both of those alternatives have that effect.
The .bind() function does a few other things that won't make any difference in a simple case like this.
edit — and definitely note the fix that #deceze posted in his answer.
Here's an example of when the two are different: if the self variable were to change, then your event handler would behave differently. It's probably not very likely that you'd change it, but it's a possibility (a bug could be introduced). With .bind(), you get a function that really can't be changed; nothing can override the binding that you set up that way.
It should be:
sub.on('change', function() {
this.param = 10;
}.bind(this))
^
misplaced parenthesis
You want to bind this for the callback function, not for on(). If you fix that, the results will be the same for your purposes.
Please also consider that there is notable performance results from both (actually they are 3) ways.
Check out https://jsperf.com/bind-vs-self-closure/17
Doing a closured reference seems to be way faster (actually 100x) than binding context.

Javascript: Illegal invocation

I am experiencing an issue. I am working with a fairly old application which has the following logic:
var Page;
var OriginalSubmit;
function init() {
Page = document.forms[0];
OriginalSubmit = Page.submit;
Page.submit = newPageSubmit;
}
function newPageSubmit() {
validate();
OriginalSubmit();
}
When the OriginalSubmit is executed, I get an Illegal invocation argument. I've read enough to understand that is because the this reference has changed (at least I think that's the case), but what I am struggling with is the correct way to fix it. The JavaScript for this is a mess, wrapped up with JSPs and global functions everywhere, so making this correct would be quite an effort, so I am looing to see if there's a chance for a less invasive solution, thanks.
When you assign OriginalSubmit = Page.submit you're obtaining a reference to the .submit() function, but when you call it as just plain OriginalSubmit() you're losing the Page context variable that will be passed as this to that function:
myObject.method(); // calls "method" with "this === myObject"
var method = myObject.method();
method(); // calls "method" with "this === window"
Instead, use this:
OriginalSubmit.call(Page); // sets "this" to "Page"
Note that even then, it's possible that re-assigning a method of a native DOM element won't work portably in all browsers, and may not work at all.

Best approach to avoid javascript's “this” mistakes in XBL

Talking about XBL is not exactly talking about javascript. So I'll create this question that's related to this one, but now about XBL, where I'm not the creator of the root javascript code, but just of the methods and event handlers inside the bindings.
--
In some cases, the this keyword may not refer to the object I expect it to. (recent example: in an key event, in my XBL)
What's the best approach to avoid this kind of mistake?
For now, I'm using always the getElementById (or $.fn from jQuery), but I'm not sure if it's the best approach.
--update
A little bit more details:
Within a XBL method the only way to access the element that was defined in the Xul file (the GUI description file) without using "this" (as it may not be the "this" I expect) is with getElementById, and this makes the code not reusable, so I'm looking for alternatives..
As you've heard elsewhere, the problem is that the this parameter isn't necessarily the object you first thought of, especially when you're talking about event handlers and the like. The best way I found is to write a small function that will bind some object as the this variable and return another function that uses the binding to call the original function.
Take a look at this code:
var bindFunction = function(self, f) {
return function() {
return f.apply(self);
};
};
var foo = function() {
alert(this.hello);
};
var bar = {
hello: "Hello there"
};
var boundFoo = bindFunction(bar, foo);
boundFoo();
What I have is a function called bindFunction that takes an object (called self) and some function, and returns another function that will call the passed-in function applying the self object as the this variable.
The rest of the code is just some test code: a foo function that will alert this.hello, a bar object with a hello member, and how you can bind foo with bar.
In essence, I've taken a function that accepts no parameters and generated another function that will ensure the first is always called with the correct this variable. Ideal for event handlers.
(Sorry, but I know nothing about XBL, so I hope this will be of use.)
If there's not a best answer, a good approach could be use javascript files instead of XBL for the implementation. Looking the Xulrunner source code, looks like most code does this.
But I still would like to use XBL, if there was a way to work fine with it..

Calling class methods within jQuery function

So I have some javascript class and in one method I use jQuery to bind function to click event. And within this function I need to call other methods of this class. In usual js function I did it through "this.method_name()", but here, I guess, jQuery redefines "this" pointer.
jQuery doesn't redefine the this pointer, but that's how JavaScript functions work in general. Store a reference to the this pointer under a different name, and use that.
var self = this;
$("selector").click(function() {
self.method_name();
});
See this answer for more approaches.
There are a few different ways to do this.
Anurag has a perfect example of one.
Two other ways are the jQuery Proxy class (Mentioned in other answers) and the 'apply' function
Now lets create an object with click events:
var MyObj = function(){
this.property1 = "StringProp";
// jQuery Proxy Function
$(".selector").click($.proxy(function(){
//Will alert "StringProp"
alert(this.property1);
// set the 'this' object in the function to the MyObj instance
},this));
//Apply Function
//args are optional
this.clickFunction = function(arg1){
alert(this.property1);
};
$(".selector").click(this.clickFunction.apply(this,"this is optional"));
};
In addition to the possibility of temporarily storing a reference to this (self = this, see Anurag's answer), since ES6 it is possible to use arrow functions for this problem. These have no "own" this.
This means that the "usual" object-related this can be accessed again within an arrow function within an event handler:
$("selector").click(() => {
this.method_name();
});
Further information:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions?retiredLocale=de#cannot_be_used_as_methods
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions?retiredLocale=de#using_call_bind_and_apply

Categories

Resources