4

So I've been doing some JavaScript class-like stuff such as

MyClass = function()
{
   var x;

   this.sayX = function()
   {
      alert(x);
   }
}

but I've also seen

MyClass = function()
{
   this.x = 0;
}

MyClass.prototype.sayX = function()
{
   alert(this.x);
}

The big question is, am I still wasting memory space in today's JavaScript engines, or are they capable of seeing the duplication in my method and optimizing them out? The reason I ask is because I'd rather do proper data hiding and not have to prefix absolutely everything with 'this'.

RandomInsano
  • 1,204
  • 2
  • 16
  • 36
  • As a note, you can use [with(this) { }](http://javascript.about.com/library/blwith.htm) if it helps you out. – Conspicuous Compiler Nov 07 '10 at 07:02
  • 4
    DO NOT use "with". It's dangerous to use and will be removed from future implementations of ECAMScript. Cannot stress this enough - it is much better to pretend that "with" does not exist in JavaScript. – Hamish Nov 07 '10 at 07:14
  • If you do it the first way, if you do any inheritance you'll need to be a lot more careful about what you do, how you mix the two techniques, when you call the super constructor, etc. – Chris Morgan Nov 20 '10 at 02:01

2 Answers2

5

The memory footprint of the first one will always be larger. Consider prototype as a shared package of methods that all instances can use. It is effective because you don't create a new function for every instance, but you're reusing the existing method already in memory.

The good news is that the two ways you showed can be combined.

MyClass = function () {
   var x;
   // public method with access 
   // to private variables
   this.sayX = function () {
      alert(x);
   };
}
// method that doesn't need access to private variables
MyClass.prototype.sharedMethod = function () {
   // ...
}

But as far as you're dealing with small codebase, you shouldn't worry about memory usage. You can even use patterns like

// everything will be created for every
// instance, but the whole thing is nicely
// wrapped into one 'factory' function
myClass = function () {
   // private variables
   var x;

   // private methods
   function doSomethingWithX() {}

   // public interface
   return {
     sayX: function () {
       alert(x);
     },
     publicMethod: function () { .. },
     // ...
   };
};

Note, I intentionally changed myClass to lowercase, because it's no longer a constructor function and there's no need to use new when invoking!


UPDATE - there's a third pattern which well suits your needs:

MyClass = function (x, y, whatever) {
   this._init.apply(this, arguments);
}

// The prototype creates a scope for data hiding.
// It also includes a constructor function.
MyClass.prototype = (function () {
   var x; // private
   return {
     _init: function (x_in) {
       x = x_in;
     },
     sayX: function () {
       alert(x);
     },
     // ...
   };
})();
gblazex
  • 49,155
  • 12
  • 98
  • 91
  • This is not strictly true ("The memory footprint of the first one will always be larger"). Imagine that there is only one object of said type in existence at a time. Although then you could perhaps argue the first case has another execution context bound... but that's even finer hairs :-) –  Nov 07 '10 at 09:25
  • Your comment is hardly constructive. If he needs only one instance of an object he creates a singleton and doesn't worry about memory footprint. – gblazex Nov 07 '10 at 09:30
  • That's very informative, but it doesn't actually answer my question at all. Can modern JavaScript engines optimize out that overhead? I may just build some tests to find out. – RandomInsano Nov 19 '10 at 23:46
  • 1
    The first sentence answers your question. The two code you showed are not identical because they have different scope chains, so **it can't be optimized**. I've updated the answer with a **third pattern**, which let's you use data hiding, uses shared function (small memory footprint), and has a constructor. *Demo:* http://jsbin.com/osixa4 – gblazex Nov 20 '10 at 01:35
  • 1
    It should be noted that the third pattern is arguably non-idiomatic as it requires the use of the `new` keyword and each instance is unique, however all instances share the same state. In some ways they're like instances, in others like singletons. Executing `five = new MyClass(5); seven = new MyClass(7); five.sayX();` yields "7". – G-Wiz Mar 29 '12 at 16:59
0

Revisiting this a huge amount later, but it turns out V8 is smart enough that it doesn't create multiple instanced of that function in the first method. Go hidden classes :D

http://www.youtube.com/watch?v=hWhMKalEicY

RandomInsano
  • 1,204
  • 2
  • 16
  • 36