Javascript scope basics : .bind or self =this? - javascript

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.

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
}

Why assign `this` to `self` and run `self.method()`?

I'm reading the source from mongoose
Collection.prototype.onOpen = function () {
var self = this;
this.buffer = false;
self.doQueue();
};
I don't understand why the author assigns this to self and runs self.doQueue(). Why not just run:
this.buffer = false;
this.doQueue();
I'm new to javascript, thanks for help.
You're right, in this instance they could have simply used this.
The use of me or self is a bit of a hack to ensure the correct context of this is used, as within JavaScript the scope of this is variant. If for example you have an event trigger a function within your class, this would be different, and wouldn't be your object that houses the function, but instead the object that called the function. To resolve this people often use me or self to ensure they're referring to the correct object... this, as in the actual object.
Just to give more clarity to #richard said earlier,
Collection.prototype.onOpen = function () {
var self = this;
this.buffer = false;
this.onclick = function(){
//do some other operations here
//if you refer `this` here then, `this` will refer to present function not the above. so to make sure it is referring to exact object people pass this to `me` or `self`
self.doQueue();
}
};
The only reason you would usually do that is if the call to doQueue() is inside a block that will change the value of this such as another function.
In this case however it doesn't serve any purpose and was probably a remnant of older code that was not changed back.
Most likely the developer wanted consistency, but failed at doing so.
Otherwise you'd be using this in some functions, self in other functions and a mix of both in other functions, depending on where you use the object and if you use nested functions/callbacks.
By always assigning this to self and then using the latter you have one additional assignment at the very beginning of each function but you always use self to access the object.
However, what the developer did in the code you posted does not make much sense. He should either use self or this both times instead of a mix that is not even necessary.
self is a copy of 'this',but it always refer to the right object,and 'this' may not.

pass variables to an event javascript - no closures, no jq, avoid evals & such

ok, this has been addressed by everybody, but yet I feel no closer to understanding what to do.
I want to have a loop that sets a bunch of click handlers and have each handler given unique parameters. I'm doing somehting like this now:
for (thisThing in things){
myDiv=document.createElement('img');
myDiv.onclick=function(){
// do somehting!
// but don't do anything with "thisThing"
// because it's got the wrong value in it by the time you call it!
// but this function has to have the value of "thisThing" to work, dammit!
}
}
All over the place the solution for this is said to be closures - wow great! except closures break ie (right?)
Elsewise, I can eval the code on the spot, baking in the varibles, but that seems ugly at best, and seems like it might break some thing
So what does this leave me? Are closures ok? is evaling ok? AM I THE ONLY PERSON DYNAMICALLY CREATING BUTTONS ON THE WEB?!? Any help will be much appreciated. sorry about the elementary &, in fact, frequently answered question.
this page has the most complete answer I've found thus far, however, it suggests that closures are the solution for all time. Curses! http://www.howtocreate.co.uk/referencedvariables.html
Closures do not break IE.
(function(someThing) {
myDiv.onclick=function(){
// Access it as "someThing"
}
})(thisThing);
jsFiddle.
The problem is the function assigned to the onclick property creates a closure where it has access to its parents variables.
By the time you are ready to click an element, its thisThing has been incremented to the final value that terminates the loop (the last property iterated over in your case) because it accesses the outer variable, not a copy.
By creating a new closure with a new self invoking function and passing thisThing, its value becomes the variable someThing and lives inside of the inner function only.
This is one of the ways of mitigating this known problem.
Note that in IE6 & 7 there is a memory leak. Consult RobG or Raynos's answer for a solution to this issue.
The problem is creating functions in loops is BAD. A little bit of refactoring makes your problem disappear.
function createDiv(thing) {
var div = ...
div.onclick = ...
}
for (thisThing in things) {
createDiv(thisThing);
}
But this still leaks memory in older versions of IE.
It's because of this code :
var div = ...;
div.onclick = function() { ...;
The div has a refence to the function and the function has a reference to the div. This is a circular reference. To remove this problem you need a callback factory.
function createDiv(thing) {
var div = ...
div.onclick = createCallback(thing);
}
function createCallback(thing) {
return function() {
...
};
}
This means your onclick callback has NO reference to your div element.
I want to have a loop that sets a
bunch of click handlers and have each
handler given unique parameters. I'm
doing somehting like this now:
> for (thisThing in things){
> myDiv=document.createElement('img');
>
> myDiv.onclick=function(){
> // do somehting!
> // but don't do anything with "thisThing"
> // because it's got the wrong value in it by the time you call it!
> // but this function has to have the value of "thisThing" to work,
> dammit!
> } }
All over the place the solution for this is said to be closures
No, you don't want closures at all. You are trying to not have closures.
except closures break ie (right?)
Wrong.
There was an issue with IE and circular references involving DOM elements causing memory leaks. That issue has largely been fixed, however it is much misunderstood. For example:
function addListener(element) {
var someVar = ...;
element.onclick = function() {
// this function has a closure to someVar
};
}
Causes a cicular reference involving the closure to someVar when addListener is called. There was some pretty simple fixes for that. What you want to do is not have a closure to someVar, but use the value. That can be done a number of ways, but the simplest is:
function addListener(element) {
var someVar = ...;
element.onclick = (function(differentVar) {
alert(differentVar);
})(someVAr);
}
So now the value of someVar is passed to differentVar, which is a local variable of the inner function. Of course the inner function may still have a closure to someVar, but the use of the use of an immediately called anonymous function breaks the closure between differentVar and someVar.
As a one-of, there is no issue with the closure anyway. But where you are attaching a number of listeners and they all have a reference to someVar, then they all share the same value. Using an immediately called anonymous function in between breaks that chain.
Edit
Sorry, that last example is incorrect, my bad.
function addListener(element) {
var someVar = ...;
element.onclick = (function(differentVar) {
return function() {
alert(differentVar);
};
})(someVAr);
}
Closures don't break IE.
for (thisThing in things){
if(!things.hasOwnProperty(thisThing)) continue;
var myDiv = new document.createElement('img');
myDiv.onclick = (function(thing){
// Instance specific vars and other thigns
return function() {
// More stuff
}
})(thisThing);
}

Object oriented design in javascript and 'this' pointer

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/

How can I keep the context of 'this' in jquery

I have something like this:
var Something = function(){
this.render = function(){};
$(window).resize(function(){
this.render();
});
}
The trouble is that inside the anonymous function 'this' refers to the window object. I know I could do something like:
var Something = function(){
this.render = function(){};
var tempThis = this;
$(window).resize(function(){
tempThis.render();
});
}
but is there a better way? This doesn't look very elegant.
The solution you found is the the one most people use. The common convention is to call your tempThis variable "that."
var Something = function(){
this.render = function(){};
var that = this;
$(window).resize(function(){
that.render();
});
};
That looks like your best option, I don't think there's a better way. (someone correct my if I'm wrong).
FYI the ability to control this is coming in the next version of JQuery
I've been doing it this way in many tight situations. It doesn't look elegant, but it never fails. Actually thats javascript closures in action.
jrh
That's exactly what I do. It's not specific to jQuery, either.
var Construct = function() {
var self = this; //preserve scope
this.materials = 2000;
this.build = function(){
self.materials -= 100;
};
};
Remember to use the var keyword in front of your new scope variable. Otherwise, you're creating a new global variable. As a local variable, it will still be accessible inside the inner function via a closure.
The best solution, to keep variables at a minimum would be to use the Function.prototype.bind() method.
var Something = function(){
this.render = function(){};
$(window).resize( this.render.bind( this ) );
}
The problem with this method that may cause future complications, which means you should choose to use it sparingly, is when you need to invoke $(this) to grab the element. So, I might suggest that it would be worthwhile to use Function.prototype.bind() in your resize method, but it would not be a good solution to use it in a click function that you might need to target the clicked element directly.
See this JSFiddle for a working example.
See the Mozilla Documentation on Function.prototype.bind() for more information
The other methods are usable, but creating a variable to maintain the context of this is the undesired effect according to your question.

Categories

Resources