I have a general question about maintaining the scope of this in an object. Here's a simplified snippet of code. Take note of the var that = this line and inside the event handler where I call that.showMenu().
var MyObj = {
init : function(target){
this.$Target = $(target);
this.$Menu = $(target).find('.menu');
this.eventBindings();
},
eventBindings : function(){
var that = this;
this.$Target.on('click', '.anchor', function(e){
e.preventDefault();
that.showMenu();
//some other code
});
},
showMenu : function(){
this.$Menu.show();
}
};
MyObj.init('.myTarget')
Code should be somewhat self explanatory. Typically I try to create reusable methods outside of my eventBindings(). The problem I continually run into is passing through this which would refer to MyObj into the event handler so I can call this.showMenu().
To overcome the obstacle I always assign this to a variable called that so when I'm further down the scope I have a reference. But I feel like this can't be the best method... can someone suggest a better alternative?
What you are doing is the best method. In Javascript this is scoped dynamically (binding depends on stack, that is on the place from where the function was called), all the other variables - are scoped statically (binding depends on static placement of variable in your code).
And since Javascript treats this in a special way, don't feel bad about treating it in a special way too.
You could encapsulate what you are doing now in a function - many libraries provide such a facility, it is usually called "bind". But this will not change what really happens, only hide it (and use up some resources while doing this). Such function could look a bit like:
function whatever (functionToProcess, thisToFreeze) {
return function() {
functionToProcess.apply(thisToFreeze, arguments); // apply is built in
}
}
Further to #Pointy's comment, using Function.prototype.bind:
onClick: function(e){
e.preventDefault();
this.showMenu();
//some other code
},
eventBindings : function(){
this.$Target.on('click', '.anchor', this.onClick.bind(this));
},
You could pass it in as event data:
this.$Target.on('click', '.anchor', {obj:this}, function(e){
e.preventDefault();
e.data.obj.showMenu();
//some other code
});
or store it on the element, but neither are really any different that declaring another variable outside like you are.
Related
If i want to call a function inside Backbone view, i have to call it like this.
this.functionName()
If i want to call the same function inside forEach Or jquery's each function, this refers to different context here. So i need to hold view's reference to some other variable and i have to use it something like below.
refresh: function () {
var view = this;
$("#list").each (function () {
view.functionName();
})
}
And finally, if i look at my view, i declare like this almost all of my functions. Did anyone find better alternative for this?
Since you are using Backbone, you would already have underscore. Using underscore you can specify context for each call.
refresh: function() {
_.each($("#list"), function() {
this.functionName()
}, this))
}
This is indeed common in Javascript, by convention they call the variable that:
var that = this
jQuery also has a proxy() function which will call a function and set the context variable (this) to something you assign: http://api.jquery.com/jQuery.proxy/
So you could do something like this:
refresh: function() {
$("#list").each($.proxy(function() {
view.functionName()
}, this))
}
But most of the times it is even more unreadable. To be honest I never use proxy() and I can't think of a good example of when to use it, but it's nice to know of it's existance, might you ever need it.
The usuals are defining either var that = this; or var self = this; or var _this = this;
The Airbnb JavaScript Style Guide which I find very sane advocates the latter. (you may want to scroll a little to find the meat).
I wonder if somebody could please help me understand something that seems odd with JS?
The below code works. The function inlineEditEvent.init() is called, and then t.copy() is called correctly (where var t = this;).
However, if I was to replace that with this.copy(), I get the error this.copy is not a function.
What's the difference here? Why does the below work, but not the way as described in the last paragraph? Thanks.
jQuery(function($){
$(document).ready(function(){inlineEditEvent.init();});
inlineEditEvent = {
init : function(){
var t = this;
/** Copy the row on click */
$('#the-list').on('click', '.row-actions a.single-copy', function(){
return t.copy();
});
}, // init
copy : function(){
// Do stuff here
}
} // inlineEditEvent
});
You're setting t as a context variable of this (of your init function). Once inside your click handler, this is now referring to the click handler, no longer the init function. Therefore, this.copy() is not a function.
this refers to this within the functions scope. That's why you need to set a self variable, so it's accessible within the scope of the function. Considering you're using jQuery, you could use $.proxy:
$.proxy(function(){
return this.copy();
},this)
t.copy(); appears in a different function to var t = this;. The value of this changes inside each function.
When you say var t= this; it refers to what this meant in that context. Later on when you are trying to refer to this, it is referring to a.single-copy instead since that is the new context it is in.
Here are two samples of code. The first one does not work and the second one does, though I'm completely at a loss as to why. Can someone explain this?
[I'm writing a simple game using a bit of jQuery to be played in a webkit browser (packaged with Titanium later).]
In the first example, Firebug tells me that "this.checkCloud" is not a function.
function Cloud(){
this.checkCloud = function(){
alert('test');
}
$("#"+this.cloudName).click(function(){
this.checkCloud();
});
}
...but then this works:
function Cloud(){
this.checkCloud = function(){
alert('test');
}
var _this = this;
$("#"+this.cloudName).click(function(){
_this.checkCloud();
});
}
This one works perfect.
Why does the first one not work? Is it because "this.checkCloud" is inside of the anonymous function?
in this example:
$("#"+this.cloudName).click(function(){
this.checkCloud();
});
this referrers to the element selected(jquery object).
what you can do is use private functions
var checkCloud = function(){
alert('test');
}
this way you can simply call it inside your anonymous function
$("#"+this.cloudName).click(function(){
checkCloud();
});
That is because the meaning of this can potentially change each time you create a new scope via a function. The meaning of this depends on how the function is invoked (and the rules can be insanely complicated). As you discovered, the easy solution is to create a second variable to which you save this in the scope where this has the expected/desired value, and then reuse the variable rather than this to refer to the same object in new function scopes where this could be different.
Try this:
function Cloud(){
this.checkCloud = function(){
alert('test');
}
var func = this.checkCloud;
$("#" + this.cloudName).click(function(){
func();
});
}
When you assign an even listener to an element, jQuery makes sure that this will refer to the element. But when you create the _this variable, you're creating a closure that jQuery couldn't mess with, even if it wanted to.
I was reading an article about Javascript's best practices, and kinda got confused about which function structure to use...
I guess it might have an impact on the scope of the variables and functions, but which one of these structures would you use (and which is considered the best practice)?
Structure 1: use the object literals.
var obj1 = {
_myvar : 'myval',
init: function() {
this.function1();
this.function2();
},
function1: function() {
alert('function1');
},
function2: function() {
alert('function2');
}
};
obj1.init();
Structure 2: Wrap the code in an auto-executing function.
(function(){
var _myvar = 'myval',
function1 = function() {
alert('function1');
},
function2 = function() {
alert('function2');
},
init = (function() {
function1();
function2();
}) ();
}) ();
You use the self-executing anonymous function when you don't want others to interfere with your code and/or don't want to use any global variable. If you might want to use those functions/objects/whatever somewhere else, you would want to use the first one.
"Structure 1" is appropriate when you need access to the methods and variables in an object from other parts of your code. That format should always be your preference when you're writing library code that's meant to be reused elsewhere.
"Structure 2" is appropriate when you don't want to share your code with other parts of the application, and so you want to protect the variables and functions from any interference from elsewhere.
I have found Christian Heilmann's Revealing Module Pattern to be quite useful. (Scroll down to the last "green screen" code sample on his page.)
With is pattern, you can create all of your methods/functions privately in an anonymously executed function and then choose your public interface via the returned object.
I'm working on a proprietary site, and I'm having some issues. I'm using jQuery along with prototype, and I've got it namespaced properly, so in this question assume you can use $ or jQ as a namespaced reference to jQuery.
So I've got a bunch of functions, some mix jQuery and javascript, some plain javascript, some jQuery only. Now, currently some functions are defined within the document.ready jQuery function, and some are defined outside of it, kind of like this:
jQ(document.ready(function($) {
if ( ifConfig ) {
//page check, function calls here
fnc1();
fnc2();
fnc3();
fnc4();
}
function fnc1() {
//fnc code in here
}
function fnc2() {
//fnc code in here
}
}); //end document.ready
function fnc3() {
}
function fnc4() {
}
Now this is all pseudo code, you can assume the functions are valid and have valid code in them. Recently I was doing some debugging, and one of my functions that was declared and called inside the document.ready said it was undefined. I moved it outside of the document.ready, and everything worked again.
I'm basically trying to understand the order of how functions are initiated/called better, so my question is when do you declare functions inside the document.ready and when do you declare them outside? Do you only declare inside when they're called within that document.ready only? Or should I always just declare them outside of that document.ready?
Thanks.
Generally, you should declare & define your own namespace, where all of your application logic (including functions/methods) is located. That way you avoid collision with other scripts on your site + that way your code is much cleaner and easier to maintenaine.
var myapp = function(){
var foobar1 = null,
foobar2 = null,
foobar3 = null;
return {
getFoobar1: function(){
return foobar1;
},
getFoobar2: function(){
return foobar2;
},
setFoobar1: function(foo){
foobar1 = foo;
},
clickhandler: function(e){
alert('I am an event handler, and I am not anonymous');
}
// etc.
};
};
$(document).ready(function(){
var Application = myapp();
Application.getFoobar2();
$(document).bind('click', Application.clickhandler);
});
That pattern (some call it the "method pattern") creates a closured function/object which also guarantees private member variables within your namespace, only accessible through the getter functions from the outside.
This is really only a pretty basic example, you can push this idea & pattern to an extend, which is very nice & a good thing (IMO).
A great book about this stuff which was named and recommended pretty often is "Javascript: The Good Parts" by Douglas Crockford.
If a function is only used inside the document ready function, then declare it inside so you don't pollute the global scope. Otherwise, declare it outside so it the rest of your script has access to those functions.
(document).ready is more used for things that need to be executed at page load, and not function declarations. If you declare them inside of (document).ready, their scope will be local to that block - if they're only used locally, that's fine and they should be declared there. Otherwise, declare them outside.
So in your example, if the functions are only used in that block, they should be declared in there. If they're used other places additionally, they should be declared outside.