Why is _this.
not working but this.
is working.
I thought the whole point of _this=this
was to provide a mechanism for when object functions are called, you have a "guaranteed" reference back to the instantiated object as it is now within the closure of the object function to mimic traditional class behavior. I've read so many pieces about scope and for some reason I'm just not seeing it. What am I missing?
var PersonClass = function PersonClass(_name, _age) {
_this=this;
this.name=_name;
this.age=_age;
console.log("created "+this.name+":"+this.age);
function changeAge(num) {
console.log("changing age for:" + _this.name);
_this.age=num;
}
PersonClass.prototype.changeAge=changeAge;
PersonClass.prototype.getAge=function() {
console.log(_this.name+":"+_this.age);
return _this.age;
};
PersonClass.prototype.getAge2=function() {
console.log(this.name+":"+this.age);
return this.age;
};
};
// ments indicate what value is displayed in console
var john=new PersonClass("john",1); // john:1
var sue=new PersonClass("sue",2); // sue:2
john.getAge(); // sue:2
john.getAge2(); // john:1
john.changeAge(10); // sue
sue.getAge(); // sue:10
sue.getAge2(); // sue:10
john.getAge(); // sue:10
john.getAge2(); // john:1
Why is _this.
not working but this.
is working.
I thought the whole point of _this=this
was to provide a mechanism for when object functions are called, you have a "guaranteed" reference back to the instantiated object as it is now within the closure of the object function to mimic traditional class behavior. I've read so many pieces about scope and for some reason I'm just not seeing it. What am I missing?
var PersonClass = function PersonClass(_name, _age) {
_this=this;
this.name=_name;
this.age=_age;
console.log("created "+this.name+":"+this.age);
function changeAge(num) {
console.log("changing age for:" + _this.name);
_this.age=num;
}
PersonClass.prototype.changeAge=changeAge;
PersonClass.prototype.getAge=function() {
console.log(_this.name+":"+_this.age);
return _this.age;
};
PersonClass.prototype.getAge2=function() {
console.log(this.name+":"+this.age);
return this.age;
};
};
// ments indicate what value is displayed in console
var john=new PersonClass("john",1); // john:1
var sue=new PersonClass("sue",2); // sue:2
john.getAge(); // sue:2
john.getAge2(); // john:1
john.changeAge(10); // sue
sue.getAge(); // sue:10
sue.getAge2(); // sue:10
john.getAge(); // sue:10
john.getAge2(); // john:1
Share
Improve this question
edited Jan 13, 2015 at 16:21
War10ck
12.5k7 gold badges44 silver badges55 bronze badges
asked Jan 13, 2015 at 15:47
sdaysday
1,05114 silver badges23 bronze badges
9
-
8
Probably because you've not
var
d it. You're also doing something very unusual with the prototyping there. The way you've written it, these should be instance methods not inherited methods – Paul S. Commented Jan 13, 2015 at 15:48 - this is a broken mish-mash of two different ways of writing "classes" in JS. – Alnitak Commented Jan 13, 2015 at 15:54
- Don't use global variables, and don't capture locals in prototype methods. – SLaks Commented Jan 13, 2015 at 15:55
- Paul - that's not it. var _this=this doesn't change anything Alnitak - how would you do it? SLaks - What do you mean by "capture". – sday Commented Jan 13, 2015 at 15:56
- stop using prototype, simplest answer. Prototype is a very old way of doing this, and it is very unnecessary, clunky, and not easily manageable. Check my answer. Works like a charm. – WebWanderer Commented Jan 13, 2015 at 16:17
3 Answers
Reset to default 4The issue is that the scope
of your internal functions is not being resolved to this
, therefore, they lose all reference to the scope created at the instanciation of new PersonClass()
. The bind
method will resolve the scope
of the internal functions to this
of the parent function class.
var PersonClass = function PersonClass(_name, _age)
{
var _this=this;
this.name=_name;
this.age=_age;
console.log("created "+this.name+":"+this.age);
this.changeAge = function(num)
{
console.log("changing age for:" + _this.name);
_this.age = num;
}.bind(this);
this.getAge = function()
{
console.log(_this.name+":"+_this.age);
return _this.age;
}.bind(this);
this.getAge2 = function()
{
console.log(this.name+":"+this.age);
return this.age;
};
};
// ments indicate what value is displayed in console
var john = new PersonClass("john",1); // john:1
var sue = new PersonClass("sue",2); // sue:2
john.getAge(); // sue:2
john.getAge2(); // john:1
john.changeAge(10); // sue
sue.getAge(); // sue:10
sue.getAge2(); // sue:10
john.getAge(); // sue:10
john.getAge2(); // john:1
Yup, that'll do it.
Hey look, it works! Here's the updated Fiddle
Just to provide more info on bind
Lets say me have an object
:
var myObj = {};
And we assign a property to that object
:
myObj.test_property = "Hello World!";
We can access that property from other properties through bind
and this
.
Lets say we make another property that's a function
:
myObj.test_func = function()
{
alert(this.test_property);
}.bind(myObj);
Wait do you guess this will do?
Because of the bind
method, the scope of this
was resolved to myObj
.
Therefore, this.test_property
is equal to myObj.test_property
, retaining the scope.
Let's go further...
We'll declare another function:
myObj.test_func2 = function(val)
{
this.test_property = val;
}.bind(myObj);
Now, lets run a test:
myObj.test_func();
myObj.test_func2("Hello Dude");
myObj.test_func();
As you can see, both test_func
and test_func2
share the same scope.
Here's a JSFiddle illustrating everything I've said about bind
When you call
new PersonClass()
at first time, prototype methods are created.
When you call
new PersonClass()
second time, prototype methods are replaced and now they has last _this in closure scope.
So, move prototype methods outside constructor function.
There are quite a few issues with your code.
_this=this;
Creates a global variable
window._this
. Use a tools like jshint to avoid this kind of bugs.PersonClass.prototype
should not be used in a constructor function. You're mixing two different object creation patterns. Inside a construction function you should use something likethis.getAge2 = function(){...}
Not necessarily a bug, but for your sample code binding this to _this is not required. This will only used when your function is not invoked on the object you've created, for example, using something like
window.setTimeout(john.getAge, 100)
This causes the getAge function to bee unbound from the john object when invoked.
Here's your code with the discussed changes (that is not to say that I remend this pattern):
var PersonClass = function PersonClass(_name, _age) {
var _this=this;
this.name=_name;
this.age=_age;
console.log("created "+this.name+":"+this.age);
function changeAge(num) {
console.log("changing age for:" + _this.name);
_this.age=num;
}
this.changeAge=changeAge;
this.getAge=function() {
console.log(_this.name+":"+_this.age);
return _this.age;
};
this.getAge2=function() {
console.log(this.name+":"+this.age);
return this.age;
};
};
var john=new PersonClass("john",1); // john:1
var sue=new PersonClass("sue",2); // sue:2
john.getAge(); // john:1
john.getAge2(); // john:1
john.changeAge(10); // john
sue.getAge(); // sue:2
sue.getAge2(); // sue:2
john.getAge(); // john:10
john.getAge2(); // john:10
window.setTimeout(john.getAge, 200); //john:10
window.setTimeout(john.getAge2, 400); // incorrect