Javascript scope issue with objects (this) - javascript

I have the following code:
var tradingInterface = function() {
this.json = '';
this.init = function() {
$.get( '/whatever',{}, function(data) {
this.json = data;
// Rebuilds Everything
this.rebuildAll();
});
};
this.rebuildAll = function() {
//whatever here
};
};
Why am I getting in init function the following error?
ReferenceError: this.rebuildAll is not defined
this.rebuildAll();
Why can I access to this.json without scoping problems but not to this.rebuildAll?
I wrote a similar previous thread but i was redirected to How to access the correct `this` / context inside a callback? but i am not able to make it work properly.
As thw thread suggets, I tried with:
var tradingInterface = function() {
this.json = '';
var self = this;
this.init = function() {
$.get( '/whatever',{}, function(data) {
this.json = data;
// Rebuilds Everything
self.rebuildAll();
});
};
this.rebuildAll = function() {
//whatever here
};
};
The error disappears but rebuildAll function is not doing what it should...
I need some help...
Regards,

The error disappears but rebuildAll function is not doing what it should...
You are not explaining what the rebuildAll is supposed to do, so I can only assume that the issue is that you didn't replace
this.json = data;
with
self.json = data;
Inside the the $.get callback, this refers to a different object than self. This is all explained in the question/answer you linked to.
Why can I access to this.json without scoping problems but not to this.rebuildAll?
You are assigning to this.json. You can (almost) always assign a property to an object. However, you are reading this.rebuildAll and try to call it as a function. Since this.rebuildAll is undefined, you cannot call it.
Simplified example:
var obj = {};
obj.foo = 42; // works, foo didn't exist before
obj.bar = function() {}; // works, bar didn't exist before
obj.bar(); // works because bar exists
obj.baz(); // doesn't work, because baz doesn't exist

Related

Uncaught ReferenceError: "method" is not defined

I've created a javascript object
var Article = function(data) {
this.foo = data,
this.get_more_data = function() {
// do something, get a response
show_data(response);
},
this.show_data = function(bar) {
//do something with bar;
}
};
which works fine when the method show_data is written without this. but then it isn't accessible outside of the object. With this. I get a "Uncaught ReferenceError" from the Chrome console.
Why is this?
Thanks.
You should be calling show_data as a method of this, not as a function scoped to the current context:
var Article = function(data) {
this.foo = data,
this.get_more_data = function() {
// do something, get a response
this.show_data(this.foo);
},
this.show_data = function(bar) {
console.log(bar);
}
};

Understanding prototyping and oops implementation in javascript

var Todo = function(x){
this.data = x;
this.view = function(){
alert("hi")
check()
}
check = function(){
alert("checking")
alert(this.data)
}
}
Todo.prototype.add = function(item){
this.data.push(item)
}
var todo = new Todo([1,2,3])
alert(todo.data)
todo.add(5)
alert(todo.data)
todo.view()
In above code why I am not able to get the value of data in check method. I am little confused.
this in the check function refers to the global object window.
Fix it with:
var Todo = function(x){
this.data = x;
this.view = function(){
alert("hi");
this.check();
};
this.check = function(){
alert("checking");
alert(this.data);
};
};
And if you don't want to expose check method public, then you could do like below.
var Todo = function(x){
this.data = x;
this.view = function(){
alert("hi")
check.apply(this); //here, by using apply method
}
var check = function(){
alert("checking")
alert(this.data)
}
}
you have declared check as a global variable:
var a = 5; local variable
a = 5; global variable (attached to window)
therefore, the function context(this) is bound to Window when calling check(), which does not contain data property.
so you have to attach check function to Todo "class":
this.check = function() {};
a side note, you could get the desired functionality by setting manually the function context to todo when invoking the function:
check.apply(todo);

TypeError xxx is not a function

All, I am struggling with an error which says TypeError: curTemplete.addSection is not a function, Please forgive that I am not familiar with the js OO, Please help to review my problem. thanks.
The code looks like below.
Templete.js
LayoutTemplete=function(currentTmpContainer,templeteId,data)
{
var curTemplete = this;
curTemplete.addSection(null, null);//this line run with error above.
this.addSection = function(uiItem, data) {
alert('ddd');
};
};
In the dom ready event.
function loadTempleteContent(templeteId)
{
var jData=[{name: 'jerry'},{name: 'mike'},{name: 'claire'}];
var tmp = new LayoutTemplete($("#currentTmpContainer"),templeteId,jData);
}
You cannot call a function before it was defined. This has nothing to do with OOP. Consider this example:
foo();
var foo = function() {
alert(42);
};
It will throw a similar error.
Define the function/the property before you access it:
this.addSection = function(uiItem, data) {
alert('ddd');
};
this.addSection(null, null);
Better yet, define addSection on the prototype, so that you don't create a new function every time you create an instances of LayoutTemplete.
LayoutTemplete = function(currentTmpContainer,templeteId,data) {
this.addSection(null, null);
};
LayoutTemplete.prototype.addSection = function(uiItem, data) {
alert('ddd');
};
Felix is trying to tell you what your issue is, here it is explicitly:
var curTemplete = this;
curTemplete.addSection(null, null);//this line run with error above.
Here you reference and attempt to call curTemplete.addection, which has not been assigned a value yet, so it resolves to undefined. When the call is attempted, undefined is not a function (as the error tells you). addSection is not defined until the assignment below:
this.addSection = function(uiItem, data) {
alert('ddd');
};
Now it's defined. Move the assignment before the call (and if you're going to assign this to a local variable, you may as well use it):
var curTemplete = this;
curTemplete.addSection = function(uiItem, data) {
alert('ddd');
};
curTemplete.addSection(null, null);

Trying to understand 'this' inside Prorotype and Lambda functions

So today I was coding an AJAX object.
I created a constructor, ajaxObj:
function ajaxObj( arg1, arg2, wrapper ) {
this.form = arg1;
this.btn = arg2;
this.msg = "Update successful";
this.url = "process.php";
this.wrap = wrapper; // this is the div the callback uses
this.serial = null; // serialized form for POSTing
this.callback = function () {
var div = document.createElement("div");
div.innerHTML = this.msg;
div.setAttribute( "id", "desiredID" );
this.wrap.appendChild(div);
}
this.btn.onclick = initXHR;
}
There were to be several objects of type ajaxObj instantiated on the given page. I wanted to include the functions that would not change and should be shared on the prototype:
ajaxObj.prototype = {
constructor: ajaxObj,
makeXHR: function () {
// cross browser XHR code returns XHR obj
}
makeSer: function () {
this.serial = $(this.form).serialize();
}
initXHR: function () {
// this is where shit gets weird!
this.makeSer(); // makeSer function doesnt exit
var http = this.makeXHR(); // makeXHR doesn't exist
http.onreadystatechange = function () {
/* this function checked for
http.status / http.readyState
and attempted to call this.callback()
which of course didn't exist.
I also tried to change instance
properties here which did not work */
}
http.open( "POST", this.url, true ); /* this.url did not work
and had to be replaced
with "process.php" */
http.setRequestHeaders("Content-Type","application/x..."); // TL;DT
http.send( this.serial ) // <--- this works just fine???
}
I've looked at many of the similar questions and given great time and consideration to this over the past week. I have my code working now, by taking callback out of the constructor as well as by taking makeXHR() and makeSer() off of the prototype and placing them all in global scope.
Despite the fact that I got my code working, to my chagrin, I still don't understand why this.url didn't work inside xhr.open() while this.serial works inside of xhr.send()
Bascally, why does 'this' work in some places of the prototype (such as replacing
ajaxObj.prototype = {
.............
initXHR: function () {
makeSer();
....
http.open( "POST", this.url, true );
....
http.send( this.serial );
....
}
with
ajaxObj.prototype = {
.............
initXHR: function () {
this.serial = $(this.form).serialize();
....
http.open( "POST", "process.php", true );
....
http.send(this.serial);
}
.... Please, un-bewilder me. I was under the impression that I had it figured out. Setting that=this inside the constructor seems to not work when I use the var keyword, and obviously(things are not always so obvious with javascript) removing the var keyword sets that equal to values were instantiated with the most recent object instance.
Just glancing over your code I can see that your initXHR function is only called when onclick of your target button fires. If you inspect this within initXHR I'm sure you'll find it is your button.
I think that based on your current class design you will need to use the old
var self = this;
in your constructor, and make your initXHR a privileged function (within your constructor) in order to access it. I've commented the code below to show you what I've added to your ctor.
function ajaxObj( arg1, arg2, wrapper ) {
// Assign this -> self at the start of the func
var self = this;
this.form = arg1;
this.btn = arg2;
this.msg = "Update successful";
this.url = "process.php";
this.wrap = wrapper;
this.serial = null;
this.callback = function () {
var div = document.createElement("div");
div.innerHTML = this.msg;
div.setAttribute( "id", "desiredID" );
this.wrap.appendChild(div);
}
// Make initXHR a privileged function, ie. one that has
// access to private variables in ctor
this.initXHR = function () {
self.url // should be accessible here
}
this.btn.onclick = this.initXHR; // Assign it.
}
Have a look at MDN's introduction to the this keyword. Probably you called the function "wrong", i.e. not on the ajaxObj instance. Show us that invocation.
The reason why this.serial works and this.url does not is that you just explicitly assigned to this.serial right before - though it likely was not a property on the object you expected.

Trying to get an object to identify its parent object without passing the parent into the child's instance

I'm having troubles finding detailed information on this issue.
I would like to instantiate Bar() within Foo() without having to pass a pointer to Foo(). Or some way for Bar() to know it's a child of Foo(). Is this possible? Or am I already using a sufficient method?
Basically, I'm trying to avoid a call like:
var bar1 = new Bar(this,someValue);
Below I have a rough example of the method I'm currently using.
function Bar(p,val) {
var par = p,
value = val;
this.__defineGetter__("value", function() {
return par.dun.value + value;
});
}
function Dun(val) {
var value = val;
this.__defineGetter__("value", function() {
return value;
});
}
function Foo() {
var dun = new Dun(15);
var bar1 = new Bar(this, 10);
var bar2 = new Bar(this, 20);
this.__defineGetter__("dun", function() {
return dun;
});
this.__defineGetter__("bar1", function() {
return bar1;
});
this.__defineGetter__("bar2", function() {
return bar2;
});
}
var myFoo = new Foo();
myFoo.bar1.value;
Thanks.
No this is not possible, since there is no built in parent/child logic in JavaScript. They are just references to objects.
Update
oh sorry, I think I misunderstood your question. I´ve asked the same question some time ago:
here. What you are trying to do, is to get the object that is "this" in the function that called the current function.
The answer is: you can´t do it...
But you could do it using the scope:
function Dun(val) {
var value = val;
this.__defineGetter__("value", function() {
return value;
});
}
function Foo() {
var dun = new Dun(15);
var bar1 = new Bar(10);
var bar2 = new Bar(20);
this.__defineGetter__("dun", function() {
return dun;
});
this.__defineGetter__("bar1", function() {
return bar1;
});
this.__defineGetter__("bar2", function() {
return bar2;
});
function Bar(val) {
this.__defineGetter__("value", function() {
return dun.value + val;
});
}
}
var myFoo = new Foo();
myFoo.bar1.value;
PS: Not related to your question, but nice to know:
since
function(val){}
is the same as
function(){
var val = arguments[0];
}
you don`t have to create a new var and pass the arguments value to it. You can use the argument variable directly.
There is no way to automatically know the this pointer of the caller of a new. So, if you want to know what that this value is without passing it as part of the constructor, then you'd have to set some semi-global state that contains the appropriate information. You could do so like this:
function Bar(val) {
var par = Bar.parent(),
value = val;
this.__defineGetter__("value", function() {
return par.dun.value + value;
});
}
// global methods and state on the Bar function
Bar.createContext = [];
Bar.push = function(o) {Bar.createContext.push(o);}
Bar.pop = function() {Bar.createContext.pop();}
Bar.parent = function() {return(Bar.createContext[Bar.createContext.length - 1]);}
function Dun(val) {
var value = val;
this.__defineGetter__("value", function() {
return value;
});
}
function Foo() {
Bar.push(this); // set global state
var dun = new Dun(15);
var bar1 = new Bar(10); // don't need to pass "this" since it's in the global state
var bar2 = new Bar(20);
this.__defineGetter__("dun", function() {
return dun;
});
this.__defineGetter__("bar1", function() {
return bar1;
});
this.__defineGetter__("bar2", function() {
return bar2;
});
Bar.pop(); // restore global state
}
var myFoo = new Foo();
myFoo.bar1.value;
And, you can see it work here: http://jsfiddle.net/jfriend00/wMgBL/
You need to give the child object one of the following:
A direct pointer from one object to another, as in your example code.
Unique information about the parent object, such that it can determine what that parent is indirectly through other means.
For example, you could store all instances of Foo in a global registry object (either an object literal or array), which the child bar object could search through. It would be looking for the object that has a child bar equal to itself.1 In this way, the fact that it is a child of Foo is the unique identifier. Unless, of course, one bar can be shared across multiple foos. Then you're hosed. :)
1: The downside to this is that you're storing every instance of Foo ever created, which means they'll never be garbage collected: you'll be leaking memory, which could be bad if your environment sticks around for a while (e.g. a node.js app).

Categories

Resources