I have a following (simplified) code:
var myModule = {
submitDummyForm: function(){
console.log(this); // the right object is logged out
var that = this; // keep a reference
$.ajax({
type:'POST',
url: 'http://localhost/',
data: {dummyData: 'something'},
dataType: 'json',
success: that.dummyFormSuccess
});
},
dummyFormSuccess: function(data){
console.log(this); // 'this' is logged out as some foreign object, most probably jQuery.ajax object
}
}
It leads to 'this' being lost in the dummyFormSuccess, no matter if I use this.dummyFormSuccess or that.dummyFormSuccessfor as an argument for my ajaxSubmitForm().
But the following code gets executed as I need:
var myModule = {
submitDummyForm: function(){
console.log(this); // the right object is logged out
var that = this; // keep a reference
$.ajax({
type:'POST',
url: 'http://localhost/',
data: {dummyData: 'something'},
dataType: 'json',
success: function(data) {
that.dummyFormSuccess(data);
}
});
},
dummyFormSuccess: function(data){
console.log(this); // now 'this' is logged out correctly as the real myModule object
}
}
I'm still not very comfortable with advanced topics of Javascript but I already know, that 'this' may get redefined, depending on where it is used. I thought if I use 'that' to store the reference to 'this', it should also keep my 'this' inside the called function. It seems weird, that I can call that.dummyFormSuccess(data) in a wrap-around function and it gets correct 'this' inside, but if I just assign it to $.ajax success, my 'this' gets lost.
Can anybody explain, where is 'this' getting lost in my case and why it works OK in the second example? Is it a problem with jQuery (maybe jQuery.ajax() overwrites my 'this' somehow in my case) or just a feature of the language?
Everything is correct. Your this is lost in a first example because you are assigning function that.dummyFormSuccess to jQuery ajax object's success. So, this way, deep inside jQuery, it's called something like ajax.success. So, this is overwritten with ajax object.
With second approach you create an anonymous function and assgn it to success. So inside your anonymous function, this points to ajax object, but that variable is accessible and have not been overwritten.
You're misunderstanding this.
The value of this parameter is determined by the callsite – the code that calls your function.
When you pass that.dummyFormSuccess or this.dummyFormSuccess, you're just passing a function that happens to come from your object.
The this or that object is just used to retrieve the function instance; it isn't bundled with the function.
When jQuery calls your callback, it always calls it in the context of the jqXHR object.
When you pass function(data) { that.dummyFormSuccess(data); }, your function expression is called in the context of this jqXHR object.
However, your callback then calls dummyFormSuccess in the context of that, so its this is what you want it to be.
You can treat 'this' in JavaScript as additional argument in function argument list.
So each call of function will contain its own value in this argument. Here are all three ways of invoking function in JS
foo(); - inside the function this will be set to default
namespace object (window in case of browser environment).
obj.foo(); - this will get obj reference inside the foo().
foo.call(obj); - 'foo' will be called with this set to obj (same as above)
Since a function can also mean an object (and it is an object), this means that function. (different scopes)
What you need to do is put var that = this; outside of dummyForm : function (the line above it), and then do console.log(that).
var that = this;
dummyFormSuccess: function(data){
console.log(that); // now 'this' is logged out correctly as the real myModule object
}
Related
I have a function, functionWithDifferentScope, that takes an object, myobject.options, as a parameter. One of the pairs in the options object is a callback which points to a function defined in myObject: myCallback.
What I'm trying to achieve is injection of the myObject namespace into the callback of a function that is defined (by a 3rd party) at the global level.
A simplified example:
var myObject = {
options: {
callback: this.myCallback(this),
...,
},
init: function() {
// functionWithDifferentScope operates in the 'window' context
functionWithDifferentScope(this.options);
},
myCallback: function(namespace) {
// 'this' is window
// 'namespace' is myObject
}
}
myObject.init();
When executing this script, this.myCallback(this) appears to be executed at definition (due to the parenthesis?); as well as once myObject.init(); is caled. During the first executions this is myObject, but subsequent calls through the functionWithDifferentScope identify this as window.
Is there a way to pass the myObject namespace to the myObject.options.callback value as a parameter?
Do you mean this?
var myObject = new (function() {
var t = this;
vac callback = function() {
// t equals to the myObject-instance
// this equals to window
}
this.init = function() {
funcWithDifferencScope(callback);
}
})();
myObject.init();
I think what you are looking for is prototype style "bind"
Basically "this.myCallback(this)" is a call to the function.
this.myCallback is the function itself. (It is an object with the type function).
You can call it using the method 'call' or 'apply' that you can use on functions. Which will call these functions.
See:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply?redirectlocale=en-US&redirectslug=JavaScript%2FReference%2FGlobal_Objects%2FFunction%2Fapply
The first argument is the object context to work in. What I think you mean by object namespace.
so: a.callback(5) is the same as a.callback.call(a,5)
However please note that these days if you are working with most javascript libraries you probably have a 'bind' function that will do the work for you.
http://prototypejs.org/doc/latest/language/Function/prototype/bind/
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind
the idea is that this.callback.bind(this) returns a Function object you can call that will inject the correct context automatically so you can pass the return value of bind alone as a callback and be assured that the method will be executed on the correct object.
I am trying to create a JavaScript object as follows.
var MyObject = function (parameters) {
this.parameters = parameters;
parameters.userFunction(this.MyObjectCallback);
}
MyObject.SOME_STATIC_VARIABLE = 21;
MyObject.prototype = {
myObjectCallback: function() {
console.log(this);
}
}
The MyObject object will accept a userFunction to which it will pass a handler. The user function will do some logic and pass the result back to the instance, for example:
new MyObject({userFunction: function(callback) {
$.post(
'http://localhost/~knyttl/source.php',
{},
callback,
'json');,
}});
Unfortunately, even though the callback is properly called, this gets an instance of the JQuery object and not of the MyObject instance as I would like. To conclude, I can not manage to keep the MyObject instance.
I am not even sure, whether this is a correct way of creating JavaScript objects. I will be grateful for any suggestion.
You can bind a specific this value using .bind. Also I corrected the capitalizing of My.
parameters.userFunction(this.myObjectCallback.bind(this));
When you call a function like a.b(), then inside b, this === a. However, if you do not directly call it but only pass the function (like a.b) and call it later, this binding is lost.
.bind returns a new function which now receives the jQuery ajax result as this. However, it ignores that and calls myObjectCallback with the predefined (bound) this.
.bind is not available on older browsers but there are shims available.
See apply() and call().
parameters.userFunction.call(this, this.MyObjectCallback);
jQuery allows you to set the context of your callback.
You are in a weird situation where you design has hurt you. Your MyObject can't be passed in as the context, because it is being created at the same time.
new MyObject({userFunction: function(callback) {
$.post(
'http://localhost/~knyttl/source.php',
{},
callback,
'json');,
}});
So instead:
var myObj = new MyObejct();
myObj.setCallback({userFunction: function (callback) {
$.ajax({
context: myObj,
url: 'http://localhost/what ever /',
success: callback,
dataType: 'json',
data: {}
}
});
Try this.
var myObject = {
obj1:function(paremeters){
this.Name = paremeters
return this},
};
I would suggest you read,
http://javascript.crockford.com/javascript.html
Using this in javascript has the potential to be very confusing. It is assigned the value of whatever is behind the dot when the function is called e.g.
window.doSomething();
will cause this to be set to window, whereas
myDOMElement.onClick();
will cause this to be set to myDOMElement.
In your case, it comes down to JQuery's internal workings, so have a look at this very thorough set of explanations to get an understanding of how JQuery handles this.
Im a bit of a beginner when it comes to javascript constructs. Im trying in jquery, but not with much success. The following is a reduces version of my code:
var field1 = {
fieldId:"#field1",
field:"",
init:function(){
this.field = this;
$.ajax({
type:"GET",
url:'some/url/to/get/values/from',
cache:false,
success: function(data){
alert(field.fieldId);
}
});
}
};
field1.init();
Basically i want to be able to print out field.fieldid inside the success event but i end up with something most definetly not expected. I would hate having to write field1.field.fieldid everytime also since that would ruin when i figure out how to use extends and similar things.
Can anyone help me get "#field1" out when i do the alert(field.fieldId) ?
This is a classic case of You must remember this. The simplest answer in your case is a local variable in your init function:
var field1 = {
fieldId:"#field1",
field:"",
init:function(){
var self = this; // <=== change here
$.ajax({
type:"GET",
url:'some/url/to/get/values/from',
cache:false,
success: function(data){
alert(self.fieldId); // <=== and here
}
});
}
};
field1.init();
Or alternately, use the context argument of the ajax function:
var field1 = {
fieldId:"#field1",
field:"",
init:function(){
// <=== change here (no `this.field = this;`)
$.ajax({
type:"GET",
url:'some/url/to/get/values/from',
cache:false,
context: this, // <=== and here
success: function(data){
alert(this.fieldId); // <=== and here
}
});
}
};
field1.init();
Basically, in JavaScript, the value of this during a function call is defined entirely by how a function is called, not where it's defined as in some other languages (C++, Java, C#, ...). When jQuery calls the success callback of the ajax function, it has to set this to something. By default, it sets it to an object representing the settings of the ajax call, but using context you can tell jQuery to set it to something else, allowing you to use this within the callback to mean the same thing as this when you call ajax.
The first solution takes advantage of the fact that the success callback is a closure over the context of the call to init (don't worry, closures are not complicated), and so by creating a variable (self) and giving it the value of this, we can reliably refer to the object via self within the closure (the success callback).
Ways in which this is set in JavaScript:
When you call a function by getting the function reference from an object property as part of the same expression as the call, this within the function call will be the object from which you got the property. So given:
var obj = {
firstName: "Fred",
speak: function(msg) {
alert(this.firstName + " says " + msg);
}
};
then
obj.speak("hi"); // alerts "Fred says hi", because `this = obj` within the call
Note that it has to be part of the same expression as the call. This does not work:
var s = obj.speak; // Getting a reference to `obj`'s `speak`
s("hi"); // alerts "undefined says hi", because `this` is not
// `obj` during the call
Using call or apply. These are features of all JavaScript functions. They let you call the function and explicitly set what this will be during the call. So given the obj above:
var s = obj.speak; // Getting a reference to `obj`'s `speak`
s.call(obj, "hi"); // alerts "Fred says hi", we explicitly made `this = obj`
// within the call
The only difference between call and apply is that when you use call, if you want to pass arguments to the function, you include them as discrete arguments to call as above (note we just passed "hi" as a second argument to call, and call passed it on as the first argument to the function). With apply, rather than an unlimited number of discrete arguments, the second argument is an array of arguments to pass to the function.
// Example 1: Passing no arguments, no difference.
// These calls do the same thing.
func.call(obj);
func.apply(obj);
// Example 2: Passing one argument (these calls do the same thing).
func.call(obj, arg);
func.apply(obj, [arg]); // note that it's in an array
// Example 3: Passing two arguments (these calls do the same thing).
func.call(obj, arg1, arg2);
func.apply(obj, [arg1, arg2]); // Again, the args are in an array
Below is just some sample Javascript that I posted that shows 2 different ways that javascript functions are being defined and called.
Is there a name for these different methods?
Which method is preferred?
The first code block looks really simple, pretty much the same as a procedural PHP function is defined and called.
The second I realize is set up more like a class/namespace it just get's a little confusing for me as I have not studied javascript too much yet. Am I correct in my thinking that all these functions could be coded in either method as the first or second code blocks and still work?
Sorry if my question is not clear enough, I will revise if needed, thanks for the help/info
initCommentsHelp();
function initCommentsHelp() {
$('#view-comments-help-a').live('click', function() {
$('#comments-help').slideToggle("normal");
return false;
});
}
VS doing this
Screenshot.Like.Shot.toggle();
Screenshot.Comment.toggle();
Screenshot.Flag.flag();
Screenshot.Flag.unflag();
var Screenshot = {
Like: {
Shot: {
toggle: function() {
if ($('.fav a.fav-toggle.processing').length == 0) {
$.ajax({
type: 'POST',
url: url,
data: data,
beforeSend: function() {
$('.fav-toggle').addClass('processing');
$link.text('Wait...');
},
success: function(responseHtml) {
$('#like-section').replaceWith(responseHtml);
}
});
}
return false;
}
},
Comment: {
toggle: function() {
var link = $(this);
var data = link.hasClass('liked-by-current-user') ? {_method: 'delete'} : null;
$.ajax({
type: 'POST',
url: this.href,
data: data,
success: function(responseHtml) {
link.closest('.comment').replaceWith(responseHtml);
}
});
return false;
}
}
},
Flag: {
// Flag a screenshot as inappropriate or Appropriate
flag: function(){
var link = $(this);
var screenshotId = link.modelId();
if(!confirm("Are you sure you want to flag this shot?"))
return false;
$.ajax({
type: 'POST',
url: this.href,
data: {
screenshot_id: screenshotId
},
success: function(responseHtml) {
$('#flag-section').html(responseHtml);
}
});
return false;
},
unflag: function() {
var link = $(this);
var screenshotId = link.modelId();
$.ajax({
type: 'POST',
url: this.href,
data: {
_method: 'delete',
screenshot_id: screenshotId
},
success: function(responseHtml) {
$('#flag-section').html(responseHtml);
}
});
return false;
}
},
};
The first way is generally preferred for writing standalone functions. You can write them as
function testFunction() {
// your code here...
}
or
var testFunction = function() {
// your code here...
}
The second example you have posted is used for namespacing your objects. You can read more about namespacing in this article : Namespacing in JavaScript
A function that's an object property (called via an object reference, e.g. obj.func()) is what's called a "method". A function not associated with an object is called a "free function". Methods have special access privileges not afforded to free functions. Exactly what those privileges are depends on the language, but all OO languages include a special variable (you can consider it a hidden parameter) available within the function body to access the object the method is bound to. In JS, the name of this parameter is this.
this exists in free functions, where it refers to the global object. You can think of free functions and global variables as being properties of a global, default object. For browsers, the global object is window. Free functions, then, are similar to global variables, which are generally bad. Free functions don't as often cause problems as global variables, but they still can, and for the same reasons. As a result, some developers use objects as namespaces to prevent name collisions.
For example, one module might create a sign function that returns whether a number is positive, negative or 0. Another module might have a sign function that digitally signs a message. These modules are created by different companies, each unaware of the other. Imagine a developer wants to use both modules. If both were defined as free functions, whichever were defined second would replace the first, wreaking havoc in the other module. To prevent this, each function can be defined as properties of separate objects.
The actual difference between free functions and methods is in how they are accessed. Methods are accessed as a property of an object, while free functions are accessed directly by name or as a variable. Note that the same function can be treated as a method or free function, depending on how you access it.
var obj = {
type: 'method',
meth: function (){
return this.type;
}
};
var func = obj.meth,
name = 'free';
// the following two lines call the same function, though `this` will be bound differently for each.
obj.meth(); // returns 'method'
func(); // returns 'free'
You can even take a free function and call it as a method in a number of ways:
function func(a, b) {
return this.foo+a+b;
}
var obj = {foo: 'bar'};
// call func as a method using the `call` method
func.call(obj, 'baz', 'bam');
// call func as a method using the `apply` method
func.apply(obj, ['baz', 'bam']);
// call func as a method in the usual way
obj.meth = func;
obj.meth(1, 2); // 'foo12'
If you look more closely at your second sample, you'll note that most of the methods use the this variable. These must remain methods; making them free functions will likely cause bugs.
One is defining the functions in an object and the other is just defining a function by itself. Functions are first class objects in JavaScript so they don't need an object to be defined.
I'm having a confusing problem using 'this' in javascript. I have a method 'get_data' which returns me some member variable of an object. Sometimes it returns to me the object itself... I have no idea why. Can someone explain what is happening here?
function Feed_Item(data) {
this.data = data;
this.get_data = function() {
return this.data;
}
this.foo = function() {
return this.foo2();
}
this.foo2 = function() {
//here type of this.data() == Feed_Item!!! It should be of type Data
}
this.bar = function() {
//here type of this.data() == Data, as I'd expect
}
}
What 'this' is in JavaScript depends on how you call the function. If 'this' is not bound to an object, this will be the window object.
If you call
item = new Feed_Item()
item.foo() //foo will be called with correct 'this'
But if you do Feed_Item(some_data), you will add a couple of functions to the global window object.
There are a lot of articles explaining this, e.g. http://www.digital-web.com/articles/scope_in_javascript/
A good blog post that explains "this" is available here: http://www.scottlogic.co.uk/2010/05/what-is-this/
Essentially the definition of this is:
The value of this is determined at the point at which the function is invoked, and is set to the object on which the function is invoked
However sometimes it's not easy to figure out exactly what that object is. This is because it depends on how the function is invoked. You can even dynamically set the value of this by invoking the function via its call method e.g.
window.str = "hello";
var fn = function(){
alert(this.str);
};
fn();
Running this code in the browser console gives hello which is the value of str on the global window object, however if you run:
fn.call({
str: 'goodbye'
}, []);
You get 'goodbye', as the context has been changed to the object passed in. Some libraries e.g. JQuery, ExtJS, ... make use of this feature to make then easier to use.