Reputation: 5880
Learning Javascript and have a question about global variables. From my reading, most recommend not to use them. However, in class based javascripting, does this unwritten rule still apply? For instance:
var width = 0;
var height = 0;
<!-- constructor -->
function Rectangle(){}
<!-- getters/setters -->
Rectangle.prototype.getWidth = function(){
return width;
}
Rectangle.prototype.setWidth = function(w){
width = w;
}
Rectangle.prototype.getHeight = function(){
return height;
}
Rectangle.prototype.setHeight = function(h){
height = h;
}
<!-- methods -->
Rectangle.prototype.area = function(){
return height * width;
}
var myRect = new Rectangle();
myRect.setWidth(5);
myRect.setHeight(4);
console.log(myRect.area()); //20
console.log(myRect.getWidth()); //5
myRect.setWidth(10);
console.log(myRect.getWidth()); //10
console.log(myRect.area()); //40
I'm familiar with Java and the ability to use access modifiers for classes, properties and methods. Is it because access modifiers do not exist in Javascript that globals should be avoided?
Upvotes: 4
Views: 3541
Reputation: 7991
It's more of a general coding standard. Global variables are evil, to be blunt.
So, let's say that you have the following code.
var width = 10;
<!-- constructor -->
function Rectangle(){}
<!-- getters/setters -->
Rectangle.prototype.getWidth = function(){
return width;
}
Rectangle.prototype.setWidth = function(w){
width = w;
}
var myRect = new Rectangle();
console.log(myRect.getWidth());
Well, that will do exactly what you would expect it to do, output 10 to the console.
But, now let's say that a developer comes in a little later, and adds a new line between constructing the myRect and the console.log like:
width=width * 10;
Now, console.log will return a 100. Well, you say, this isn't so bad. I can still read this.
But let's modify the last two lines to be:
var myRect = new Rectangle();
doSomethingCool();
console.log(myRect.getWidth());
function doSomethingCool() {
LOTS o code;
width = "10px"; // I need this to update the style sheet.
LOTS o code;
}
Suddenly it's much more difficult to figure out what's actually happening.
Sure the console.log will output 10px, but why did it happen?
Upvotes: 1
Reputation: 2339
Usually in OO JavaScript you create a closure with the class definition to avoid polluting the global scope.
var Rectangle;
(function() {
var width = 0;
var height = 0;
Rectangle = function (){}
...
})(); // the () execute the function with the closure
This way you are able to define private properties and still have a clean global space :)
Also, to prevent the problem MДΓΓ БДLL described in the comment while still keeping the private properties and getter/setters, this is the way to go
function Rectangle() {
// Private properties
var width = 0,
height = 0;
// Public methods using private properties
this.setWidth = function(value) {
width = value;
}
this.setHeight = function(value) {
height = value;
}
}
Much easier is anyway to use public properties as stated in other answer, unless you really care for the integrity of the width
and height
vars.
Upvotes: 1
Reputation: 123428
You would probably use this code instead
<!-- constructor -->
var Rectangle = function(w, h) {
this.width = w || 0;
this.height = h || 0;
}
<!-- getters/setters -->
Rectangle.prototype.getWidth = function( ) { return this.width; }
Rectangle.prototype.setWidth = function(w) { this.width = w; }
Rectangle.prototype.getHeight = function() { return this.height; }
Rectangle.prototype.setHeight = function(h) { this.height = h; }
<!-- methods -->
Rectangle.prototype.area = function(){
return this.height * this.width;
}
var myRect = new Rectangle(5, 4);
console.log(myRect.area()); //20
console.log(myRect.getWidth()); //5
myRect.setWidth(10);
this.width
and this.height
, otherwise you will modify the global width and height variables and those values won't be tied to the single instance of Rectangle.var Rectangle = function(w, h) { ... }
rather than function Rectangle() { ... }
.Upvotes: 3
Reputation: 360016
does this unwritten rule still apply?
Yes, you should always avoid globals. I don't know why width
and height
are declared outside of Rectangle
in your code. You need to make heavy use of this
:
function Rectangle(h, w) {
this.height = h || 0;
this.width = w || 0;
}
<!-- getters/setters -->
Rectangle.prototype.getWidth = function(){
return this.width;
}
Rectangle.prototype.setWidth = function(w){
this.width = w;
}
Rectangle.prototype.getHeight = function(){
return this.height;
}
Rectangle.prototype.setHeight = function(h){
this.height = h;
}
<!-- methods -->
Rectangle.prototype.area = function(){
return this.height * this.width;
}
Is it because access modifiers do not exist in Javascript that globals should be avoided?
No. Globals should always be avoided, regardless of the programming language.
Upvotes: 3
Reputation: 25868
To get this to behave how you are expecting, you will need to create instance properties, rather than using the global variables width
and height
. Your current method would result in multiple Rectangle
instances using the same variables.
Try:
function Rectangle () {
this.width = 0;
this.height = 0;
}
Rectangle.prototype.setWidth = function(w) {
this.width = w;
};
etc...
As others have noted, the global variables width
and height
will be shared by all other code in the current scope (NB. JavaScript only has function-level scoping, not block-level).
Upvotes: 2
Reputation: 230531
Yes, it's still true. You should avoid global variables at all times.
In your example width
and height
are global. If this is the full code, it's not so much of a problem. But what if you later decide to introduce another "class" called, say, GameField
. It also has width and height, naturally. I smell trouble here.
Upvotes: 0
Reputation: 236162
The simple reason for avoiding global variables at all costs is, that you can never be sure which other scripts get loaded at the same time. So to avoid conflicts which might end up in real ugly error scenarios, you should at least wrap your own code into one closured
function context.
(function() {
// all of your code here
}());
This simple pattern totally avoids any conflict.
Upvotes: 2
Reputation: 191058
Globals should be avoided. You should wrap stuff in closures.
Only use globals when you want to expose functionality.
Upvotes: 1