40

The javascript prototype-based object-oriented programming style is interesting, but there are a lot of situations where you need the ability to create objects from a class.

For instance in a vector drawing application, the workspace will usually be empty at the beginning of the drawing : I cannot create a new "line" from an existing one. More generally, every situation where objects are being dynamically created require the use of classes.

I've read a lot of tutorials and the book "Javascript : the good parts", but yet it seems to me that there is no way to define classes that respect 1) encapsulation and 2) efficient member methods declaration (I mean : member methods that are being defined once, and shared among every class instances).

To define private variables, closures are being used :

function ClassA()
{
    var value = 1;
    this.getValue = function()
    {
        return value;
    }
}

The problem here is that every instance of "ClassA" will have its own copy of the member function "getValue", which is not efficient.

To define member functions efficiently, prototype is being used :

function ClassB()
{
    this.value = 1;
}

ClassB.prototype.getValue = function()
{
    return this.value;
}

The problem here is that the member variable "value" is public.

I don't think that this issue can be solved easily, since "private" variables need to be defined DURING object creation (so that the object can have access to its context of creation, without exposing thoses values) whereas prototype-based member functions definition has to be done AFTER object creation, so that prototype makes sense ("this.prototype" does not exists, I've checked).

Or am I missing something ?


EDIT :

First of all, thank you for your interesting answers.

I just wanted to add a little precision to my initial message :

What I really want to do is to have 1) private variables (encapsulation is good, because people only have access to what they need) and 2) efficient member methods declaration (avoid copies).

It seems that simple private variables declaration can really only be achieved via closure in javascript, that's essentially why I focused on the class based approach. If there is a way to achieve simple private variables declaration with a prototype based approach, that's okay for me, I'm not a fierce class-based approach proponnent.

After reading the answers, it seems like the simple solution is to forget about privates, and use a special coding conventions to detter other programmers from accessing "private" variables directly...

And I agree, my title / first sentence was misleading regarding the issue I wanted to discuss here.

Benjamin Gruenbaum
  • 270,886
  • 87
  • 504
  • 504
thomasc
  • 935
  • 9
  • 18
  • 17
    "but there are a lot of situations where you **need** the ability to create objects from a class" - no. and technically enforced private variables are also not necessary. Just prefix them with an underscore and tell people that those are internal. – ThiefMaster Jun 09 '13 at 09:08
  • 1
    read this [The most misunderstood Programming language-Javascript](http://www.crockford.com/javascript/javascript.html) and then this [private members in javascript](http://www.crockford.com/javascript/private.html) – pinkpanther Jun 09 '13 at 09:16
  • @ThiefMaster I wouldn't go so far: that's why properties were added to javascript: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty – Jan Turoň Jun 09 '13 at 09:20
  • 3
    @pinkpanther OP has basically shown Crockford's approach (which you're linking to) in his question. @ OP On topic, ES6 will bring actual classes and private members, for that and an ES3-5 fallback see http://blog.niftysnippets.org/2013/05/private-properties-in-es6-and-es3-and.html – Fabrício Matté Jun 09 '13 at 09:23
  • @ThiefMaster Yeah, it seems, unfortunately, that using a coding convention to show that some member variables should not be modified directly is the way to go to keep things simple... – thomasc Jun 09 '13 at 09:32
  • @FabrícioMatté: Yeah, my answer had an issue, it does keep the variable private but shared across instances, which might be fine for other cases. I think convention is the way to go here too. But I guess you could get clever with closures somehow. – elclanrs Jun 09 '13 at 09:36
  • Since there is no concept of visibility for properties, you are right, you cannot have both. Using closures is just a "hacky" way to create "private properties". The language was not designed for that, so it's not surprising that any approach to "solve" this has drawbacks. ES6 will introduce a way to encapsulate data though: http://wiki.ecmascript.org/doku.php?id=harmony:private_name_objects. – Felix Kling Jun 09 '13 at 09:42
  • @Andy: Well, I'd say that keeping the memory footprint as small as possible is desirable in a web application. – Felix Kling Jun 09 '13 at 09:45
  • @AndyRay `There is nothing inefficient about every class having a copy of a method.` Sure mate. – Jon Koops Jun 09 '13 at 10:02
  • 1
    I wrote up [**an answer**](http://stackoverflow.com/a/13214563/1615483) that covers this to [**a similar question**](http://stackoverflow.com/q/13213928/1615483) last year. Basically, it's all about scope. – Paul S. Jun 09 '13 at 10:07
  • @FabrícioMatté A class in ES6 is just the current functionality in disguise. – Florian Margaine Jun 09 '13 at 10:11
  • @FelixKling So a language with first-class functions was not designed for closures? It's a known and wanted side-effect that closures give "private" variables. – Florian Margaine Jun 09 '13 at 10:12
  • Aight, got a new answer, just something quick I put together but maybe an idea to improve? – elclanrs Jun 09 '13 at 10:13
  • @FlorianMargaine closure is good to have scoped variables that won't interfer with other scopes. It's more like a namespace where variables can be defined to not mess with global scopes. Having private members is nothing else than a side effect. Private variables in object oriented programming aren't required in any way. – Loïc Faure-Lacroix Jun 09 '13 at 10:15
  • Can you tell me what is your problem with a value being publicly available? – Loïc Faure-Lacroix Jun 09 '13 at 10:17
  • @Florian: I said "private **properties**" not "private variables". Of course closures are great to encapsulate data. But inside a constructor function they are used to the simulate "private properties", at least that's how I see it. – Felix Kling Jun 09 '13 at 11:06
  • @ThiefMaster There are edge-cases that you need to be really careful when doing that. If B inherits A and both A and B have a "private" variable that has the same name, they will share the exact same value and it will most likely cause hard to debug unexpected behavior. As a good rule of thumb, don't ever do that if you need inheritance. – HoLyVieR Jun 09 '13 at 15:35

8 Answers8

31

Shh, come here! Wanna hear a secret?

Classical inheritance is a tested and tried approach.

It is useful to implement it in JavaScript often. Classes are a nice concept to have and having templates for modeling our world after objects is awesome.

Classical inheritance is just a pattern. It's perfectly OK to implement classical inheritance in JavaScript if it's the pattern you need for your use case.

Prototypical inheritance focuses on sharing functionality and that's awesome (dinasaur drumstick awesome), but in some cases you want to share a data-scheme and not functionality. That's a problem prototypical inheritance does not address at all.

So, you're telling me classes are not evil like everyone keeps telling me?

No, they are not. What the JS community frowns upon is not the concept of classes, it's limiting yourself to just classes for code reuse. Just like the language does not enforce strong or static typing, it doesn't enforce schemes on object structure.

In fact, behind the scene clever implementations of the language can turn your normal objects to something resembling classical inheritance classes.

So, how do classes work in JavaScript

Well, you really only need a constructor:

function getVehicle(engine){
    return { engine : engine };
}

var v = getVehicle("V6");
v.engine;//v6

We now have a vehicle class. We didn't need to define a Vehicle class explicitly using a special keyword. Now, some people don't like to do things this way and are used to the more classical way. For this JS provides (silly imho) syntactic sugar by doing:

function Vehicle(engine){
     this.engine = engine;
}
var v = new Vehicle("V6");
v.engine;//v6

That's the same thing as the example above for the most part.

So, what are we still missing?

Inheritance and private members.

What if I told you basic subtyping is very simple in JavaScript?

JavaScript's notion of typing is different than what we're used to in other languages. What does it mean to be a sub-type of some type in JS?

var a = {x:5};
var b = {x:3,y:3};

Is the type of b a sub type of the type of a? Let's say if it is according to (strong) behavioral subtyping (the LSP):

<<<< Begin technical part

  • Contravariance of method arguments in the subtype - Is fully preserved in this sort of inheritance.
  • Covariance of return types in the subtype - Is fully preserved in this sort of inheritance.
  • No new exceptions should be thrown by methods of the subtype, except where those exceptions are themselves subtypes of exceptions thrown by the methods of the supertype. - Is fully preserved in this sort of inheritance.

Also,

All of these are again, are up to us to keep. We can keep them as tightly or loosly as we want, we don't have to, but we surely can.

So matter of fact, as long as we abide to these rules above when implementing our inheritance, we're fully implementing strong behavioral subtyping, which is a very powerful form of subtyping (see note*).

>>>>> End technical part

Trivially, one can also see that structural subtyping holds.

How would this apply to our Car example?

function getCar(typeOfCar){
    var v = getVehicle("CarEngine");
    v.typeOfCar = typeOfCar;
    return v;
}
v = getCar("Honda");
v.typeOfCar;//Honda;
v.engine;//CarEngine

Not too hard, was it? What about private members?

function getVehicle(engine){
    var secret = "Hello"
    return {
        engine : engine,
        getSecret : function() {
            return secret;
        }
    };
}

See, secret is a closure variable. It's perfectly "private", it works differently than privates in languages like Java, but it's impossible to access from the outside.

What about having privates in functions?

Ah! That's a great question.

If we want to use a private variable in a function we share on the prototype we need to firrst understand how JS closures and functions work.

In JavaScript functions are first class. This means you can pass functions around.

function getPerson(name){
    var greeting = "Hello " + name;
    return {
        greet : function() {
            return greeting;
        }
    };
}

var a = getPerson("thomasc");
a.greet(); //Hello thomasc

So far so good, but we can pass that function bounded to a around to other objects! This lets you do very loose decoupling which is awesome.

var b = a.greet;
b(); //Hello thomasc

Wait! How did b know the person's name is thomasc? That's just the magic of closures. Pretty awesome huh?

You might be worried about performance. Let me tell you how I learned to stop worrying and started to love the optimizing JIT.

In practice, having copies of functions like that is not a big issue. Functions in javascript are all about well, functionality! Closures are an awesome concept, once you grasp and master them you see it's well worth it, and the performance hit really isn't that meaningful. JS is getting faster every day, don't worry about these sort of performance issues.

If you think it's complicated, the following is also very legitimate. A common contract with other developers simply says "If my variable starts with _ don't touch it, we are both consenting adults". This would look something like:

function getPerson(name){
    var greeter = {
        greet : function() {
            return "Hello" +greeter._name;
        }
    };
    greeter._name = name;
    return greeter;
}

Or in classical style

function Person(name){
    this._name = name;
    this.greet = function(){
       return "Hello "+this._name;
    }
}

Or if you'd like to cache the function on the prototype instead of instantiate copies:

function Person(name){
    this._name = name;
}
Person.prototype.greet =  function(){
       return "Hello "+this._name;
}

So, to sum it up:

  • You can use classical inheritance patterns, they are useful for sharing types of data

  • You should also use prototypical inheritance, it is just as potent, and much more in cases you want to share functionality.

  • TheifMaster pretty much nailed it. Having privates private is really not a big deal as one might think in JavaScript, as long as your code defines a clear interface this should not be problematic at all. We're all concenting adults here :)

*The clever reader might think: Huh? Weren't you tricking me there with the history rule? I mean, property access isn't encapsulated.

I say no, I was not. Even if you don't explicitly encapsulate the fields as private, you can simply define your contract in a way that does not access them. Often like TheifMaster suggested with _. Also, I think the history rule is not that big of a deal in a lot of such scenarios as long as we're not changing the way property access treats properties of the parent object. Again, it's up to us.

Community
  • 1
  • 1
Benjamin Gruenbaum
  • 270,886
  • 87
  • 504
  • 504
  • 2
    Your `getCar()` is composition, not inheritance :-) – Florian Margaine Jun 09 '13 at 10:34
  • @FlorianMargaine I beg to differ. My getCar is inheritance, it returns a vehicle, it follows the [LSP](http://en.wikipedia.org/wiki/Liskov_substitution_principle) just fine :) It's subtyping, only not in the Java way, but subtyping nontheless. – Benjamin Gruenbaum Jun 09 '13 at 10:36
  • In Java/C#, wouldn't you call this composition? Let's call apples apples. Composition is some kind of subtyping. In JS, inheritance goes through prototypes. – Florian Margaine Jun 09 '13 at 10:39
  • @FlorianMargaine No. Subtyping is not about calling apples apples. It's a _well defined_ computer science concept. If you follow the [LSP](http://en.wikipedia.org/wiki/Liskov_substitution_principle) you're doing subtyping, period. Note, I'm returning an object created by the Vehicle constructor, I'm extending it by adding another property to it. In languages like Java/C# this wouldn't be possible – Benjamin Gruenbaum Jun 09 '13 at 10:42
  • 3
    I would like to point out something that's often missed by people implementing "classes" in js: You are limiting the way your code behaves, like any form of encapsulation. js at its core is prototypical, so the fact that you can implement classes in it indicates that the former is more abstract and more powerful (implementing prototypical inheritance in a classical language is much more difficult). Yegge said it before: http://steve-yegge.blogspot.com/2008/10/universal-design-pattern.html – Zirak Jun 09 '13 at 10:55
  • 1
    Benjamin, your post is simply awesome. I could not have said it any better myself. I built that jTypes library that Aadit hates so much, and I think you hit the nail on the head. Classical inheritance is simply a design pattern, and a very good one at that. jTypes simply converts classical inheritance-like definitions into a prototype-chained instance matrix for you. It does all of the dirty work of moving throughout the instance matrix, and lets you focus strictly on your class implementations, while still working in a very powerful language such as JavaScript. – redline Jun 09 '13 at 11:08
  • Not to mention, most people sit here saying prototypal inheritance is very powerful and that using classical inheritance is extremely limiting. Well, I obviously agree that prototypal inheritance is very powerful, but classical inheritance is a very useful design pattern. And to their point, jTypes actually allows you to use the "prototype" keyword to define members on the prototype chain itself, so you can still define "normal" JavaScript classes using prototypes which just have an instance matrix built on top. Giving you the best of both worlds by allowing you to pick and choose methods. – redline Jun 09 '13 at 11:13
  • @redline - Don't get me wrong. I don't hate the classical inheritance pattern. It's awesome. What I do hate is thinking of constructors inheriting from other constructors in JavaScript. That is wrong. In JavaScript objects inherit from other objects. Classes have been around longer than prototypes and classical inheritance allows for better optimized code. In fact I love using classical inheritance patterns in my code (a la [`augment`](https://github.com/javascript/augment)). The only reason I dislike to your library jTypes is because implementing virtual base classes, etc. in JS is overkill. – Aadit M Shah Jun 09 '13 at 11:17
  • Then you are completely missing the point like many others. There is more to coding than just performance. Design patterns and frameworks are created to make things easier. Having abstract/virtual members is a big part of the classical inheritance design pattern. When you try to scale up a framework in JavaScript, it quickly becomes a daunting task to organize and separate your code. Classes, along with the concepts in classical inheritance, solve these problems. So if you can use both prototypal inheritance for performance and classical inheritance for design, what's stopping you? – redline Jun 09 '13 at 11:21
  • And to your point about constructors, jTypes makes it OPTIONAL to call the base constructor, and still lets you specify static and prototype members as well. So there is absolutely nothing to lose by using it. Am I recommending that you use a jTypes class for every type of object that you define? Certainly not. Prototypal inheritance will run circles around jTypes, but if you're not instantiating thousands of objects per second, a classical inheritance design pattern can simplify your larger classes. – redline Jun 09 '13 at 11:25
  • And most importantly, the only performance hit that you take is when you instantiate the classes. After that, you are left with nothing more than a matrix of objects that all use prototypes to inherit from one another. But instead of having a singular chain of prototypes, you have three chains for your private, protected, and public instances. Anyone could have defined these classes in a similar fashion using native JavaScript prototypes, but it would have been such a long, tedious, and daunting task, and the performance benefits of doing it that way over jTypes are negligible. – redline Jun 09 '13 at 11:28
  • 1
    I developed quite a bit in JS now and I was completely unaware of the syntactic suggar you pointed out. The role of `this` in JS just became a whole lot clearer to me, thanks for that! – Mene Jun 09 '13 at 12:46
  • In your example about binding, shouldn't it be `var b = a.greet;` instead of `var b = a.greet();`? Otherwise it's a call and `b` would just hold `greeting`. – Mene Jun 09 '13 at 12:48
  • 1
    @Mene Of course! Thanks for the catch, that's what I get for writing a lot of code in the SO editor :) – Benjamin Gruenbaum Jun 09 '13 at 13:15
  • In total agreement @BenjaminGruenbaum – pixel 67 Mar 31 '14 at 07:15
  • Halleluja! @BenjaminGruenbaum :) – SandeliusME Jun 16 '16 at 11:31
28

I don't want to be discouraging since you seem to be a fairly new member of StackOverflow, however I'm going to have to be a little in your face and say that it's a really bad idea to try to implement classical inheritance in JavaScript.

Note: When I say that it's a bad idea to implement classical inheritance in JavaScript I mean that trying to simulate actual classes, interfaces, access modifiers, etc. in JavaScript is a bad idea. Nevertheless, classical inheritance as a design pattern in JavaScript is useful as it's just syntactic sugar for prototypal inheritance (e.g. maximally minimal classes). I use this design pattern in my code all the time (a la augment).

JavaScript is a prototypal object-oriented programming language. Not a classical object-oriented programming language. Sure, you can implement classical inheritance on top of JavaScript but before you do keep the following things in mind:

  1. You're going against the spirit of the language, which means that you'll be faced with problems. Lots of problems - performance, readability, maintainability, etc.
  2. You don't need classes. Thomas, I know that you truly believe that you need classes but trust me on this. You don't.

For your sake I'll provide two answers to this question. The first one will show you how to do classical inheritance in JavaScript. The second one (which I recommend) will teach you to embrace prototypal inheritance.

Classical Inheritance in JavaScript

Most programmers start with trying to implement classical inheritance in JavaScript. Even JavaScript Gurus like Douglas Crockford tried to implement classical inheritance in JavaScript. I too tried to implement classical inheritance in JavaScript.

First I created a library called Clockwork and then augment. However I wouldn't recommend you to use either of these libraries because they go against the spirit of JavaScript. The truth is that I was still an amateur JavaScript programmer when I wrote these classical inheritance libraries.

The only reason I mention this is because everyone is an amateur at some point of time, and although I would prefer that you didn't use classical inheritance patterns in JavaScript, I can't expect you to understand why prototypal inheritance matters just yet.

You can't learn how to cycle without falling down a few times. I believe you're still in the learning phase with respect to prototypal inheritance. Your need for classical inheritance is like the training wheels on cycles.

Nevertheless, training wheels are important. If you want there are some classical inheritance libraries out there which should make you more comfortable writing code in JavaScript. One such library is jTypes. Just remember to take off the training wheels when you are confident of your skills as a JavaScript programmer.

Note: Personally I don't like jTypes one bit.

Prototypal Inheritance in JavaScript

I'm writing this section as a milestone for you so that you can come back later and know what to do next when you are ready to learn about true prototypal inheritance.

First of all the following line is wrong:

The javascript prototype-based object-oriented programming style is interesting, but there are a lot of situations where you need the ability to create objects from a class.

This is wrong because:

  1. You will never need to create objects from a class in JavaScript.
  2. There is no way to create a class in JavaScript.

Yes it's possible to simulate classical inheritance in JavaScript. However you're still inheriting properties from objects and not classes. For example, ECMAScript Harmony classes are just syntactic sugar for the classical pattern of prototypal inheritance.

In the same context the example you gave is also wrong:

For instance in a vector drawing application, the workspace will usually be empty at the beginning of the drawing : I cannot create a new "line" from an existing one. More generally, every situation where objects are being dynamically created require the use of classes.

Yes you can create a new line from an existing one even though the workspace is empty in the beginning. What you need to understand is that the line is not actually drawn though.

var line = {
    x1: 0,
    y1: 0,
    x2: 0,
    y2: 0,
    draw: function () {
        // drawing logic
    },
    create: function (x1, y1, x2, y2) {
        var line = Object.create(this);
        line.x1 = x1;
        line.y1 = y1;
        line.x2 = x2;
        line.y2 = y2;
        return line;
    }
};

Now you can draw your the above line by simply calling line.draw or else you could create a new line from it:

var line2 = line.create(0, 0, 0, 100);
var line3 = line.create(0, 100, 100, 100);
var line4 = line.create(100, 100, 100, 0);
var line5 = line.create(100, 0, 0, 0);

line2.draw();
line3.draw();
line4.draw();
line5.draw();

The lines line2, line3, line4 and line5 form a 100x100 square when drawn.

Conclusion

So you see you really don't need classes in JavaScript. Objects are enough. Encapsulation can be easily achieved using functions.

That being said you can't have public functions of each instance access the private state of the object without each instance having its own set of public functions.

This is not a problem however because:

  1. You don't really need private state. You may think that you do, but you really don't.
  2. If you really want to make a variable private then as ThiefMaster mentioned just prefix the variable name with an underscore and tell your users not to mess with it.
Community
  • 1
  • 1
Aadit M Shah
  • 72,912
  • 30
  • 168
  • 299
  • 1
    [Link to the chatroom for further discussion of this post](http://chat.stackoverflow.com/rooms/31479/discussion-between-jon-koops-and-aadit-m-shah) – Andrew Barber Jun 09 '13 at 12:06
4

Aight, here's my attempt at solving this particular issue, although I think following conventions it's a better approach, ie. prefix your variables with _. Here I just keep track of the instances in an array, they can then be removed with a _destroy method. I'm sure this can be improved but hopefully it will give you some ideas:

var Class = (function ClassModule() {

  var private = []; // array of objects of private variables

  function Class(value) {
    this._init();
    this._set('value', value);
  }

  Class.prototype = {

    // create new instance
    _init: function() {
      this.instance = private.length;
      private.push({ instance: this.instance });
    },

    // get private variable
    _get: function(prop) {
      return private[this.instance][prop];
    },

    // set private variable
    _set: function(prop, value) {
      return private[this.instance][prop] = value;
    },

    // remove private variables
    _destroy: function() {
      delete private[this.instance];
    },

    getValue: function() {
      return this._get('value');
    }
  };

  return Class;
}());

var a = new Class('foo');
var b = new Class('baz');

console.log(a.getValue()); //=> foo
console.log(b.getValue()); //=> baz

a._destroy();

console.log(b.getValue()); //=> baz
elclanrs
  • 92,861
  • 21
  • 134
  • 171
  • You don't actually because it's in the prototype. – elclanrs Jun 09 '13 at 09:14
  • @Givi: Nah, I think you need to read up on that a bit more. When you create a new instance its `__proto__` property is set to reference the same object as its internal prototype (its constructor's prototype object), there is no duplication as objects in JS are always references. – elclanrs Jun 09 '13 at 09:17
  • @elclanrs - Say I create an instance `a` and then an instance `b`. Then I call `_destroy` upon `a`. What does `b.getValue()` return? See the demo: http://jsfiddle.net/3B5c6/ You have a problem. – Aadit M Shah Jun 09 '13 at 10:20
  • @AaditMShah: Check edit. A quick solution would be to just `delete` the object but keep the index intact. This wouldn't be too bad, large arrays lookups are fine and you're probably not going to have thousands of instances anyway (or destroy them that often...) – elclanrs Jun 09 '13 at 10:30
  • @elclanrs - No offense but your solution seems to be overkill. Yes JavaScript has it's limitations, but working around them is usually not feasible because JavaScript was never designed to be extensible. Instead of trying to use JavaScript the way you want to use it it's better to simply use JavaScript for what it is. If you really want to create your own Domain Specific Language then LISP is the perfect choice. Extend it as much as you want using macros. That's what I love about LISP. – Aadit M Shah Jun 09 '13 at 10:54
  • Your edited answer looks pretty clean, +1 for fixing and extending it. `=]` – Fabrício Matté Jun 09 '13 at 11:07
  • @FabrícioMatté: I sometimes get crazy playing with these abstractions. I see this going where this went: https://gist.github.com/elclanrs/5668451 – elclanrs Jun 09 '13 at 11:21
  • @elclanrs Looks like a nice level of abstraction `=]` back on topic, making a property that is only a key to an array of private objects is pretty clean, basically just as clean as [TJ's approach](http://blog.niftysnippets.org/2013/05/private-properties-in-es6-and-es3-and.html) (naming private variables randomly), just that yours lack the non-enumerability but that's just a detail. – Fabrício Matté Jun 09 '13 at 11:30
  • FYI Array lookups are only fine because engines optimize them very close to C array whenever they *can*. If you use delete, then they *can't*, and it will not be fine. Neither arrays or hash tables lose performance as the size grows so the huge size of the array is not a problem performance-wise. – Esailija Jun 14 '13 at 14:53
2

You don't need private/public at runtime. These are enforceable statically. Any project complex enough to enforce private properties are not used outside will have a build/pre-process step, which you can use to verify the fact. Even languages with syntax for private/public have a way to access private at runtime.

As for defining class-based objects, the constructor+prototype you are using is the simplest and most efficient way. Any kind of additional wizardry will be more complex and less performant.

Although you can cache prototype so you don't have to repeat ClassB.prototype. all the time:

//in node.js you can leave the wrapper function out
var ClassB = (function() {
    var method = ClassB.prototype;

    function ClassB( value ) {
        this._value = value;
    }

    method.getValue = function() {
        return this._value;
    };

    method.setValue = function( value ) {
        this._value = value;
    };

    return ClassB;
})();

The above does not require any library and you can easily create a macro for it.

Also, in this case even a regex is enough to verify that "private" properties are used correctly. Run /([a-zA-Z$_-][a-zA-Z0-9$_-]*)\._.+/g through the file and see that the first match is always this. http://jsfiddle.net/7gumy/

Esailija
  • 138,174
  • 23
  • 272
  • 326
1

It's impossible as far as I know without other instances influencing the value, so if it's a constant you're still good by wrapping it in a function like this:

(function( context ) {

    'use strict';

    var SOME_CONSTANT = 'Hello World';

    var SomeObject = function() {};

    SomeObject.prototype.sayHello = function() {
        console.log(SOME_CONSTANT);
    };

    context.SomeObject = SomeObject;

})( this );

var someInstance = new SomeObject();
someInstance.sayHello();

The best you could do is annotate that a property shouldn't be touched by using an underscore like this._value instead of this.value.

Note that private functions are possible by hiding them in a function:

(function( context ) {

    'use strict';

    var SomeObject = function() {};

    var getMessage = function() {
        return 'Hello World';
    };

    SomeObject.prototype.sayHello = function() {
        console.log(getMessage());
    };

    context.SomeObject = SomeObject;

})( this );

var someInstance = new SomeObject();
someInstance.sayHello();

Here is an example of 2 'Classes' extending and interacting with each other: http://jsfiddle.net/TV3H3/

Jon Koops
  • 8,801
  • 6
  • 29
  • 51
1

If you really want private entities on a per instance basis, but still want to inherit your methods, you could use the following set-up:

var Bundle = (function(){
  var local = {}, constructor = function(){
    if ( this instanceof constructor ) {
      local[(this.id = constructor.id++)] = {
        data: 123
      };
    }
  };
  constructor.id = 0;
  constructor.prototype.exampleMethod = function(){
    return local[this.id].data;
  }
  return constructor;
})();

Now if you create a new Bundle, the data value is locked away inside:

var a = new Bundle(); console.log( a.exampleMethod() ); /// 123

However you now get into the debate as to whether you should truly have private values in JavaScript. As far as I've found it's always better for those that may need to extend your code—even yourself—to have open access to everything.

There are also hidden downsides to the above pattern, besides not being so readable, or being clunky to access "private" values. One fact is that every single instance of Bundle will retain a reference to the local object. This could mean—for example—if you created thousands of Bundles, and deleted all but one of them, the data held in local would not be garbage collected for all Bundles ever created. You'd have to include some deconstruction code to fix that... basically making things more complicated.

So I'd recommend dropping the idea of private entities / properties, whichever pattern you decide to go for... object-based or constructor. The benefit of JavaScript is that all these different approaches are possible—it's no-where-near as clear cut as class-based languages—which some could argue makes things confusing, but I like the freedom JavaScript lends towards being quick and expressive.

Pebbl
  • 34,937
  • 6
  • 62
  • 64
1

with regards this statement in your question:

For instance in a vector drawing application, the workspace will usually be empty at the beginning of the drawing : I cannot create a new "line" from an existing one. More generally, every situation where objects are being dynamically created require the use of classes.

You seem to be under the misunderstanding that objects in Javascript can only be made by cloning existing objects, which would backtrack to the problem of "okay but what about the very first object? that can't be made by cloning an existing object because there aren't any existing objects."

However you can make objects from scratch, and the syntax for that is as simple as var object = {}

I mean, that's the simplest possible object, an empty object. More useful of course would be an object with stuff in it:

var object = {
  name: "Thing",
  value: 0,
  method: function() {
    return true;
  }
}

and so on, and now you're off to the races!

jhocking
  • 5,527
  • 1
  • 24
  • 38
0

There are cleverer people than I answering this question, but I wanted to note one part in particular that you just edited in - the private variable part.

You can simulate this using closures; an awesome construct which allows a function to have it's own environment. You could do this:

var line = (function() {
  var length = 0;
  return {
    setLen : function (newLen) {
      length = newLen;
    },
    getLen : function () {
      return length;
    }
  };
}());

This will set line to be an object with the setLen and getLen methods, but you'll have no way of manually accessing length without using those methods.

jackweirdy
  • 5,632
  • 4
  • 24
  • 33