Javascript class variables - this. or var - javascript

Should 'this.' or 'var' be used to create variables in a Javascript class or does it not matter which is used. Obviously those defined with this. will be accessible from outside the object whereas those defined with var will not but are there any other differences?
function myClass() {
this.count = 0;
this.oTimer = null;
this.getCount = function() { return(this.count); }
}
oMyObj = new myClass();
oMyObj.getCount(); // returns 0
as opposed to
function myClass2() {
var count = 0;
var oTimer = null;
this.getCount = function() { return(count); }
}
oMyObj = new myClass2();
oMyObj.getCount(); // returns 0

Trying to explain a little bit more in detail than Dominique in the comments:
if you use the var keyword, the variable is only valid in the scope they are run. This means that after the constructor is run (the function body), the variables get lost (as they were only valid inside the constructor).
If you want to access the variables outside of the constructor (e.g. member-methods), you have to bind the variables to the class itself via the this keyword. Now their scope is the class itself, not just the constructor.
Edit:
Explaining further: while you can use the variables declared with var inside of methods that you also declared inside the constructor because they are defined in the same scope (see example of Question), it is not possible to access them through any other added methods that you add via Function.prototype.
To show this, I have created a little JSFiddle example
So it is generally better practice to define all variables of a class (that you don't only intent to use as temporary variables inside the constructor) with the this keyword.

Related

What is it called when a function behaves like a class but doesn't use the class keyword, nor "new" keyword (in Javascript)?

I looked through the suggested links but can't seem to find the term for a function that acts like a class (is it a constructor function? doesn't have that keyword either!) but doesn't use the new keyword, nor class.
I've used both this example's pattern and the class pattern in my code but realized I don't know how to describe the former.
I think this is in part because I learned JS recently, have seen class thrown around a lot, yet looking through my notes of not-ES5,6,7,2018,2020 etc. can't seem to find what var aCounter = counterFunction() is called for the life of me.
I know what the result of what i'm doing is, how to work it, etc. but why no constructor(), no new, no class, no etc.prototype.etc pattern? I know i'm creating an object, calling a method existing Within the object, etc. I believe i'm beginning to ramble.
Lo, an example
const counterFunction = () => {
let val = 0
return {
increment() { val++ },
getVal() { return val }
}
}
which is || can be instantiated (?) like so:
let aCounter = counterFunction() // where i'm getting tripped up
and works like
aCounter.increment() // 1
aCounter.increment() // 2
aCounter.getVal() // 2
I know this is rambling, but help! I think it will make things click more inside once this lexical puzzle piece is put into position!
That is just a function that returns an object literal, which does not act like a class (doesn't have a prototype, and as you pointed out, does not use new, etc).
The functions that are set as the properties of this object (which you store in aCounter) seem to act like class methods because they keep the reference to the variable val alive, but this is not because val is in any way associated with the actual object.
Instead, those functions are closures that keep the reference to the variable alive for as long as the functions themselves are alive.
So to answer your question, what you have described doesn't have any name in particular. It's just a function that returns an object.
Edit:
You asked why there is no constructor() or related syntax in this pattern. Object literals in JavaScript are just mappings of names and values:
const x = { a: 3, b: "hello" };
You do not need a constructor for this, and there is no prototype because it was not instantiated using a constructor. On the other hand, classes and constructor functions are templates for objects that will be created later, and those objects do have a prototype and a constructor because the template contains logic that initializes the object.
class A
{
constructor()
{
this.a = new Date();
this.b = this.a.toString(); // you cannot do this in an object literal
}
}
const x = new A();
Question:
What is it called when a function behaves like a class but doesn't use the class keyword, nor “new” keyword (in Javascript)?
Answer:
It's called a "factory function".
Factory functions usually return a object of a consistent type but are not instances of the factory function itself. Returned objects would rarely inherit from the factory function's prototype property, and calling the factory function does not require new before the function being called.
What you showed there is nothing special. It is just a normal function that has a closure.
Though, you can call it as a type of design pattern.
It looks similar to Revealing Module Pattern where you can separate public property and private property.
Below is an example (not a good one tho):
var counter = function(){
var privateCount = 0;
var privateHistory = [];
return {
getVal: function(){
return privateCount;
},
increment: function(){
privateCount++;
privateHistory.push('+');
return this.getVal();
},
decrement: function(){
privateCount--;
privateHistory.push('-');
return this.getVal();
},
publicHistory: function(){
return privateHistory;
}
}
}
var aCounter = counter();
console.log(aCounter.increment());
console.log(aCounter.decrement());
console.log(aCounter.publicHistory());
Here, you can't directly manipulate the private variables that I don't expose to you.
You can only manipulate those private variables only if I expose the function to you. In this case, the .increment() and .decrement() function.
As you can see, there is no class, no prototype, no constructor.
I can see how you may get tripped up, let's go through your code and explore what's going on:
const counterFunction = () => {
let val = 0
return {
increment() { val++ },
getVal() { return val }
}
}
At this point counterFunction is a variable that points to a function, it's essentially a function name. The ()=>{...} is the function body or function definition and within it the return statement shows that it returns an unnamed object with two property methods.
let aCounter = counterFunction() // where i'm getting tripped up
This is calling your previously defined function, which again returns the object with two methods and assigns it to the variable aCounter. If you did the same thing again for a variable called bCounter they would hold two independent objects.
and works like
aCounter.increment() // 1
aCounter.increment() // 2
aCounter.getVal() // 2
Because the method inside the object refers to a variable outside the scope of the object, but within the function body, a closure is created so that the state of val may be retained. Because the variable is in use, the browser's cleanup process skips over it, so the function is still kept in memory, I believe until the object is destroyed and the function's variable is no longer used.

Javascript Class properties and methods work differently

I have been working with javascript for a while and always used this notation to create objects
var className = (function() {
var property = 1; //Example of a property
var method = function () {
//Example of a method
};
});
but now I have a project where I use AngularJs and the javascript don't recognize it. I can use this one
var className = (function() {
this.property = 1; //Example of a property
this.method = function() {
//Example of a method
};
});
Is there any reason for the first one not working? In my experience I prefer the first one better
[Edit]
var className = (function() {
var property = 1; //Example of a property
var method = function () {
//Example of a method
};
})();
var className = (function() {
var property = 1; //Example of a property
var method = function () {
//Example of a method
};
});
In this example you're not actually creating anything that surmounts to a property and/or method. You're simply assigning a function to the variable className, and within that function you're creating two more variables. Variables are function-scoped, and by definition, won't be visible outside the function.
If you use AngularJS, then there are different scopes and understanding of OOP. You should probably must know $scope which is the scope for Angular objects, methods etc. Please check the documentation, also read more about Angular scopes.
In your case, you should have this code in some controller or service (factory, directive) and have something like this:
angular.module('myapp', [])
.controller('MyCtrl', ['$scope', function($scope) {
$scope.myvar = 'hello';
$scope.mymethod = function() {
console.log($scope.myvar);
};
}])
Those 2 examples do 2 very different things.
In the first, you're not actually creating any properties on the newly created object when calling className(). Anything declared using var in a function is just a locally-scoped value to that function, meaning you can't access it once you leave that function.
The second will actually create the properties property and method on the newly created object. However, when defining constructor functions it's much more common to do it like this:
function ClassName() {
this.property = 'some property value'
}
Constructor functions are typically capitalized, but this is just a style guide thing.
And then define member functions on the constructor's prototype like this:
ClassName.prototype.method = function() {
// function body where "this" refers to an instance of ClassName
}
Then you can use the constructor like this:
var someObject = new ClassName()
To understand this behavior, you need to understand how JavaScript handles scope.
The only scope within JavaScript is function scope. To understand what this means, consider the other types of scope you see in other programming languages, such as loops, classes, and if-else statements. When you create a variable within a scope, it can not be accessed outside that scope.
Because the only JavaScript scope is function scope, these two methods are functionally identical:
function myFunc(){
var x = 5; // variable declared outside loops
for(var i = 0; i < x; i++){ // iterator variable declared in loop params
var y = i; // variable declared inside a loop
for(var i = 10; i > 6; i--){
var z = i; // variable declared inside another loop
}
}
}
function myFunc(){
var x, i, y, z; // all variables declared at beginning of function
x = 5;
for(i = 0; i < x; i++){
y = i;
for(i = 10; i > 6; i--){
z = i;
}
}
}
Notice that in JavaScript, it's a logic error to use the same iterator variable in for loops in the same scope, since they will refer to the same variable (there's no "loop scope" to distinguish them).
On the other hand, function scope can be used to prevent variable names from colliding, since variables can't be accessed outside their scope.
Notice in the example below we have two different variables named x. They are different because they exist in different function scopes.
var x = "Outer Scope";
(function(){
var x = "Inner Scope";
alert(x); // output: "Inner Scope"
})();
alert(x); // output: "Outer Scope"
There's no way for the outer scope to access the value of x in the inner scope.
That brings us to the JavaScript way of creating object-like syntax.
In your first example, the variables property and method cannot be accessed outside of the "constructor" or "class definition" (or whatever you want to call the function you'll use to create objects) because they're wrapped up in a function scope. You can practically think of them as private members.
In your second example, you're using the this keyword to attach the variables as attributes of the object returned by your "constructor". The object attributes can be accessed by code outside the function scope. Think of them as public members.
If it helps put things into an object-oriented frame of reference, you can even use that syntax to provide getters and setters (accessors and mutators), like so.
var className = function() {
var property = 1;
this.getProperty = function(){return property;};
this.setProperty = function(value){property = value;};
};
var obj = new className();
obj.getProperty(); // 1
obj.setProperty(200);
obj.getProperty(); // 200
typeof(obj.property); // "undefined"
The getProperty() and setProperty() functions are able to access the property because they were defined within the same function scope; to understand this more clearly, look up "closures."
From a performance perspective, you may not want to have many functions defined in your "class definition" as above, since that results in each instance of the object having its own copy of the function (which increases the amount of memory each object requires). Instead, you can attach methods to the prototype of the function, so the methods are defined once.
className.prototype.getDouble = function(){return this.getProperty()*2;};
obj.getDouble(); // 400
A big thing to note is that prototype functions are also bound by function scope, so they can't access variables that you defined in the "class definition."
className.prototype.getTriple = function(){return property*3;};
obj.getTriple(); // ERROR: "'property' is undefined"

Difference between using a module pattern and instantiating new objects

I'm trying to restructure some javascript and I'm confused about the module pattern.
One way I have now is to simply declare a class containing all the functionality for a component like so
var Foo = function(){
this.Bar = {};
...
}
and create a new instance for use in the component. But I've also read about the module pattern and I can't see what the benefit would be compared to what I have since it appears to do about the same, just in a more complicated way. Maybe I just haven't encountered the case that makes it a better choice.
For example, a pattern like this:
var module = (function () {
// private variables and functions
var foo = 'bar';
// constructor
var module = function () {
};
// prototype
module.prototype = {
constructor: module,
something: function () {
}
};
// return module
return module;
})();
var my_module = new module();
doesn't appear significantly different from what I already had. What does this pattern let me do that I can't do the other way?
The key difference between the two is in the first example, you can't have private variables and functions if you want to work with the prototype. You can have private variables and functions, but only if your public properties and methods are created in the constructor by attaching them to this.
Example 1 with a private variable and function:
var Foo = function(){
var privateVar = "priv";
function privateFunction(){
console.log(privateVar);
}
this.publicProperty = 1;
this.publicFunction = function(){
console.log(privateVar);
}
}
The above is no problem if you don't want to use the prototype. However, if you do then there is no way to have private variables, without the new scope that your second example benefits from.
As you can see, you have to include everything within the constructor, whereas the second example you can leave the constructor just for initialising variables.
Conversely, the prototype methods in the second example are out of scope of the constructor, so they can't use any variables of functions within the constructor. All functions and variables that the prototype methods need must be declared in the outer closure scope.

How to use scope in JavaScript for Function constructor?

If I were to make a new function using the Function constructor, how could I give it a non-temporary scope to access besides window (meaning the scope only has to be evaluated once, not every time the function is called)? The purpose is to construct multiple variables that require some pretty costly calculations, and I don't want to reconstruct them every time the function is called, but I also don't want to store them in window. Any ideas?
You could bind your function to the specific context using bind keyword:
var context = {};
var f = new Function("args", "return this").bind(context);
f(); // context
Since bind is defined in ECMA 5th, it may not be present in all browsers, here's a workaround
For the above described purpose, you use static functions. You cannot prevent scope from being evaluated at every call, because this is the way JavaScript works, but you can speed it up by not having window in the scoping chain.
var namespace = {};
namespace.someMethod = function() {
// do something here.
};
Now anywhere in your code, you can call that method by using namespace.someMethod();. Just be careful. The above is a static method. You can call it without instantiating. But you MUST NOT use this.property inside a static function. It is a potentially very dangerous operation, as it may give an extension access to the global object and basically un-restricted permissions.
And the above is a static JavaScript method. It does not have window in the scoping chain.
Here's how to create a constructor using the same pattern. When you want to use a constructor, you always instantiate before using. For that you have the new keyword.
var namespace = {};
namespace.coordinate = function(x, y) {
this.x = x;
this.y = y;
};
namespace.coordinate.prototype.addCoordinates = function() {
return this.x + this.y;
};
Now anywhere in your code you can do:
var coordinateObject = new namespace.coordinate(5,10);
// you have created a new instance.
alert(coordinateObject.addCoordinates());// will alert 15;
// now you can make as many as you want. They will behave as instances.
// This means they do not interfere with each other in any way.
// They just have the same properties and methods, but the instance values
// Can be entirely different.
var secondCoordinateObject = new namespace.coordinate(10, 25);
alert(secondCoordinateObject.addCoordinates());// will output 35.
You have successufully created an instance of your namespace.coordinate class. Using the pattern I gave you, you can replicate almost the entire functionality of Java or C or any other Object Oriented language.
var yourNamespace = {
func1: function() {
},
func2: function() {
}
};
...
yourNamespace.func1();
you can call the function that you want by calling the function from name space like this yourNamespace.func1();
The ever-growing method of creating, storing, hiding, revealing, and grouping variables & functions is through the magic of "closures", Javascript's most powerful and yet unsung feature:
var groupObj = (function (setUp) {
// maintained by reference, hidden
var _priVar = setUp * 2;
// maintained by reference, revealed (through returned object)
var _pubVar = 8;
var _pubFunc = function (x) {
_priVar += x;
_pubVar += x;
}
var lostVar = setUp * 99; // not referenced, hidden, so evaporates!
return {
'pubVar' : _pubVar,
'pubFunc' : _pubFunc
}
}(4)); // runs immediately with 4 as setUp, revealing pubVar & pubFunc
Then...
groupObj.pubFunc(7); // runs public function, adds 7 to both variables
alert('public variable: ' + groupObj.pubVar); // alerts public variable
A closure occurs whenever there is a function inside of another function. A variable inside of the outter function will be maintained so long as it is referenced by the inner function, kind of a "no-mans land" where a variable is forced to exist by a reference to it from a lower scope, but is hidden from the higher scope due to the innate principles of Javascript.
There are a few other ways to use closures, replacing the object constructor, one-off conflict-free private functions, and more. There are many posts here about them.

Why do I have to use "this" to access in inner property of a function

What is the difference between
function person(first_name, last_name) {
this.first = first_name
this.last = last_name
}
and this:
function person(first_name, last_name) {
var first = first_name
var last = last_name
}
Why only the first one makes person.first & person.last accessible outside the function?
The this keyword within a function is called the invocation context.
1) If you define your function as a member of an object (a method):
myObject.someMethod = function() { this.x = 2; };
then the invocation context, this, is the object to which the method is being added, myObject. So after calling myObject.someMethod(); above, myObject.x is then 2. The member x is undefined until you call the method, unless you defined it before.
2) If you use your function as a constructor with the new keyword, then this refers to the new object that is being created:
function MyX() { this.x = 3; };
var myX = new MyX();
You'll then have property myX.x set to 3.
Note that I called my constructor MyX(), not myX(). You should call yours Person(), not person(). It's just a convention, but it is useful to indicate that a function is meant to be used as a constructor.
3) Finally, if you use this within a function that you call as neither a method nor a constructor, then this refers to the global object (document or, equivalently, window). Note however that if you are using javascript in strict mode (which you should do), this is undefined in such a situation, which means that you basically cannot use this in a function that is not a method or a constructor.
Your specific question refers to case 2), the constructor. this.x = 3 in the constructor just sets property x of the newly created object. After some object myX is created, you can then access and modify x externally as any other object property using myX.x.
when you write constructor function ( using new) - you add properties using this.XXX
then you do :
var p = new Person('s','d');
and then you have access to p.first etc.
in the second example :
youre not creating any properties..
youre only creating private variables.
so you cant access them...
By using this.something you're saying that THIS is an object and something is his property.
By using var, you're saying that it's just a variable and not a property.
More information about variable vs property:
http://javascriptweblog.wordpress.com/2010/08/09/variables-vs-properties-in-javascript/
Because of function scope.
A variable lifetime is between the curly braces of the function. The this keyword allows to access the function properties outside of it.
Definitely take a look at this link: https://developer.mozilla.org/en/JavaScript/Reference/Functions_and_function_scope
'var' keyword make a variable scoped. In the last example var first and var last create variable accessible only in the scope of the function. You can see this as a local variable in a constructor.
when in javascript you declare a variable as
var variable
it only exists inside the method where you declared it. If you want a variable to be accessible for everyone (that is, global) it has to be declared without the 'var' part
You do not necessarily have to use this. It'd also work fine if you've got a structure like this:
Person = function(first_name, last_name) {
var first, last;
create(first_name, last_name);
function create(first_name, last_name) {
first = first_name
last = last_name
}
return {
firstName: first,
lastName: last
}
}

Categories

Resources