Are there any downsides to using a JavaScript "class" with this pattern?
var FooClass = function()
{
var private = "a private variable";
this.public = "a public variable";
var privatefn = function() { ... };
this.publicfn = function() { ... };
};
var foo = new FooClass();
foo.public = "bar";
foo.publicfn();
Classes are a template for creating objects. They encapsulate data with code to work on that data. Classes in JS are built on prototypes but also have some syntax and semantics that are not shared with ES5 class-like semantics.
In JavaScript, you don't! You can write any program you want without utilizing classes or the this keyword ever! Indeed, the class syntax is somewhat new to JavaScript, and object oriented code was written with functions beforehand. The class syntax is just syntactic sugar over that function-based approach to OOP.
JavaScript didn't originally have classes. Classes were added with the introduction of ECMASCRIPT 6 (es6), a new and improved version of JavaScript (ECMASCRIPT 5 being the older version). A typical JavaScript class is an object with a default constructor method.
There are two types of Class in ES6: parent class/super class: The class extended to create new class are know as a parent class or super class. child/sub classes: The class are newly created are known as child or sub class. Sub class inherit all the properties from parent class except constructor.
What you're doing in your example isn't the "class" pattern people think of in JS -- typically people are thinking of the more "normal" class model of Java/C#/C++/etc which can be faked with libraries.
Instead your example is actually fairly normal and good JS design, but for completeness i'll discuss behaviour differences you'll see between the private and public "members" you have
var private = "a private variable";
this.public = "a public variable";
Accessing private
from within any of your functions will be quite a lot faster than accessing public
because the location of private
can be determined reasonably well just with a static lookup by the JS engine. Attempts to access public
require a lookup, most modern JS engines perform a degree of lookup caching, but it is still more expensive than a simple scoped var access.
var privatefn = function() { ... };
this.publicfn = function() { ... };
The same lookup rules apply to these functions as with the above variable accesses, the only real difference (in your example) is that if your functions are called, say privatefn()
vs this.publicfn()
, privatefn
will always get the global object for this
. But also if someone does
f = foo.publicfn;
f();
Then the call to f
will have the global object as this
but it will be able to modify the private
variable.
The more normal way to do public functions however (which resolves the detached public function modifying private members issue) is to put public functions on the prototype, eg.
Foo.prototype.publicfn = function() { ... }
Which forces public functions to not modify private information -- there are some times where this isn't an option, but it's good practice as it also reduces memory use slightly, take:
function Foo1() {
this.f = function(){ return "foo" };
}
vs
function Foo2() {
}
Foo2.prototype.f = function(){ return "foo" };
In Foo1
you have a copy of the function object for every instance of Foo1
(not all the emory, just the object, eg. new Foo1().f !== new Foo2().f
) whereas in Foo2
there is only a single function object.
That's good so far, but there's another access level you've left out.
this.publicfn
is really a priveleged method as it has access to private members and functions.
To add methods which are public but not priveleged, modify the prototype as follows:
FooClass.prototype.reallypublicfn = function () { ... };
note that this method does not have access to private members of FooClass but it is accessible through any instance of FooClass.
Another way of accomplishing this is returning these methods from the constructor
var FooClass = function()
{
var private = "a private variable";
this.public = "a public variable";
var privatefn = function() { ... };
this.publicfn = function() { ... };
return {
reallypublicfn: function () { ...}
}
};
var foo = new FooClass();
foo.public = "bar";
foo.publicfn();
Basically, these methods of data hiding help you adhere to traditional OOP techniques. Generally speaking, improving data-hiding and encapsulation in your classes is a good thing. Ensuring low coupling makes it much easier to change things down the road, so publicly exposing as little as possible is really to your benefit.
See https://developer.mozilla.org/en/Introduction_to_Object-Oriented_JavaScript for a simple overview and http://www.crockford.com/javascript/private.html for details on how to accomplish these things.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With