Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JavaScript "classes"

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();
like image 795
cdmckay Avatar asked Jul 25 '09 03:07

cdmckay


People also ask

What are classes in JavaScript?

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.

Should I use classes in JavaScript?

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.

Is there a class in JavaScript?

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.

What are ES6 classes?

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.


2 Answers

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.

like image 133
olliej Avatar answered Sep 28 '22 08:09

olliej


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.

like image 30
Jonathan Fingland Avatar answered Sep 28 '22 06:09

Jonathan Fingland