In C++, the language I'm most comfortable with, usually one declares an object like this:
class foo
{
public:
int bar;
int getBar() { return bar; }
}
Calling getBar()
works fine (ignoring the fact that bar
might be uninitialized). The variable bar
within getBar()
is in the scope of class foo
, so I don't need to say this->bar
unless I really need to make it clear that I'm referring to the class' bar
instead of, say, a parameter.
Now, I'm trying to get started with OOP in Javascript. So, I look up how to define classes and try the same sort of thing:
function foo()
{
this.bar = 0;
this.getBar = function() { return bar; }
}
And it gives me bar is undefined
. Changing the bar
to this.bar
fixes the issue, but doing that for every variable clutters up my code quite a bit. Is this necessary for every variable? Since I can't find any questions relating to this, it makes me feel like I'm doing something fundamentally wrong.
EDIT: Right, so, from the comments what I'm getting is that this.bar
, a property of an object, references something different than bar
, a local variable. Can someone say why exactly this is, in terms of scoping and objects, and if there's another way to define an object where this isn't necessary?
To get closer to OOP in JavaScript, you might want to take a look into a Module design pattern (for instance, described here).
Based on the closure effect, this pattern allows emulating private properties in your objects.
With 'private' properties you can reference them directly by its identifier (i.e., no
this
keyword as in constructors).But anyway, closures and design patterns in JS - an advanced topic. So, get familiar with basics (also explained in the book mentioned before).
In javascript
this
always refers to the owner object of the function. For example, if you define your functionfoo()
in a page, then owner is the javascript objectwindows
; or if you define thefoo()
on html element<body>
, then the owner is the html element body; and likewise if you define the function onclick of element<a>
, then the owner is the anchor.In your case, you are assigning a property
bar
to the 'owner' object at the begining and trying to return the local variablebar
.Since you never defined any local varialbe
bar
, it is giving you as bar is undefined.Ideally your code should have defined the variable as
var bar;
if you want to return the value zero.JavaScript has no
classesclass-based object model. It uses the mightier prototypical inheritance, which can mimic classes, but is not suited well for it. Everything is an object, and objects [can] inherit from other objects.A constructor is just a function that assigns properties to newly created objects. The object (created by a call with the
new
keyword) can be referenced trough thethis
keyword (which is local to the function).A method also is just a function which is called on an object - again with
this
pointing to the object. At least when that function is invoked as a property of the object, using a member operator (dot, brackets). This causes lots of confusion to newbies, because if you pass around that function (e.g. to an event listener) it is "detached" from the object it was accessed on.Now where is the inheritance? Instances of a "class" inherit from the same prototype object. Methods are defined as function properties on that object (instead of one function for each instance), the instance on which you call them just inherits that property.
Example:
So, we did only use properties of that object and are happy with it. But all of them are "public", and can be overwritten/changed/deleted! If that doesn't matter you, you're lucky. You can indicate "privateness" of properties by prefixing their names with underscores, but that's only a hint to other developers and may not be obeyed (especially in error).
So, clever minds have found a solution that uses the constructor function as a closure, allowing the creating of private "attributes". Every execution of a javascript function creates a new variable environment for local variables, which may get garbage collected once the execution has finished. Every function that is declared inside that scope also has access to these variables, and as long as those functions could be called (e.g. by an event listener) the environment must persist. So, by exporting locally defined functions from your constructor you preserve that variable environment with local variables that can only be accessed by these functions.
Let's see it in action:
This getter function, which is defined inside the constructor, is now called a "privileged method" as it has access to the "private" (local) "attributes" (variables). The value of
bar
will never change. You also could declare a setter function for it, of course, and with that you might add some validation etc.Notice that the methods on the prototype object do not have access to the local variables of the constructor, yet they might use the privileged methods. Let's add one:
So, you can combine both approaches. Notice that the privileged methods need more memory, as you create distinct function objects with different scope chains (yet the same code). If you are going to create incredibly huge amounts of instances, you should define methods only on the prototype.
It gets even a little more complicated when you are setting up inheritance from one "class" to another - basically you have to make the child prototype object inherit from the parent one, and apply the parent constructor on child instances to create the "private attributes". Have a look at Correct javascript inheritance, Private variables in inherited prototypes, Define Private field Members and Inheritance in JAVASCRIPT module pattern and How to implement inheritance in JS Revealing prototype pattern?
When you call the function above with the
new
keyword - like this...... - a few things happen:
1) an object is created
2) the function is executed with the
this
keyword referencing that object.3) that object is returned.
foo
, then, becomes this object:Why not, then, just do this:
You would, if it's just that one simple object.
But creating an object with a constructor (that's how it's called) gives us a big advantage in creating multiple of the "same" objects.
See, in javascript, all functions are created with a prototype property [an object], and all objects created with that function (by calling it with the new keyword) are linked to that prototype object. This is why it's so cool - you can store all common methods (and properties, if you wanted to) in the prototype object, and save a lot of memory. This is how it works:
That's it!
Explicitly saying
this.foo
means (as you've understood well) that you're interested about the propertyfoo
of the current object referenced bythis
. So if you use:this.foo = 'bar';
you're going to set the propertyfoo
of the current object referenced bythis
equals tobar
.The
this
keyword in JavaScript doesn't always mean the same thing like in C++. Here I can give you an example:In the example above we're calling the function
Person
with the context of the functionDeveloper
sothis
is referencing to the object which will be created byDeveloper
. As you might see from theconsole.log
resultthis
is comes fromDeveloper
. With the first argument of the methodcall
we specify the context with which the function will be called.If you don't use
this
simply the property you've created will be a local variable. As you might know JavaScript have functional scope so that's why the variable will be local, visible only for the function where it's declared (and of course all it's child functions which are declared inside the parent). Here is an example:This is true when you use the
var
keyword. This means that you're definingbar
as local variable if you forgetvar
unfortunatelybar
will became global.Exactly the local scope can help you to achieve privacy and encapsulation which are one of the greatest benefits of OOP.
Real world example:
One more example of the benefits of the JavaScript scope is the Module Pattern. In Module Pattern you can simulate privacy using the local functional scope of JavaScript. With this approach you can have both private properties and methods. Here is an example:
There's a little strange syntax with the parentless wrapping the anonymous functions but forget it for the moment (it's just executing the function after it's being initialized). The functionality can be saw from the example of usage but the benefits are connected mainly of providing a simple public interface which does not engages you with all implementation details. For more detailed explanation of the pattern you can see the link I've put above.
I hope that with
this
:-) information I helped you to understand few basic topics of JavaScript.this is like a public access modifier of objects(variables or functions), while var is the private access modifier
Example