Correct way to build classes in JavaScript?
Asked Answered
S

3

6

I am new to JavaScript, and trying to understand how i should write classes (my background in 'regular' OO languages, such as java and c++).

I understand that i have two options:

  1. If i want my class to have private methods and members i can't define them in the prototype. But in that case, they will be built for each new object created (memory issue).

  2. If i define methods in the class prototype, i will have no encapsulation (this is weird for me, as a java/c++ developer :P).

Which of the two methods you use? why?

Seville answered 13/5, 2011 at 15:13 Comment(3)
Read here: crockford.com/javascript/inheritance.htmlDur
Also this: javascript.crockford.com/private.htmlDur
Take a look at OOP BasicsBoothman
H
7

So, I don't think there's a "right answer" to this question...it's basically what you prefer and think is best for your particular use. Many of my classes are "Static classes", e.g.

var MyClassName = {
    methodName: function() { },
    //...
}

As I never need to instantiate them. When I need to instantiate multiple instances, I use the prototype method.

If you NEED private variables, you could define a function/class to do private variables, and the methods that need to access those private vars within that function/class. Then, use the prototype method for all methods that don't need access to the private vars. E.g.

var PageClass = function() {
    var _birthdate;

    this.getBirthdate = function() {
        return typeof(_birthdate) == "undefined" ? null : _birthdate;
    }
    this.setBirthdate = function( date ) {
        if( typeof(date) == 'object' && date.constructor == Date ) {
            _birthdate = date;
        }
        else {
            throw "Invalid Argument Exception: PageClass.setBirthdate expects parameter of type 'Date'";
        }
    }
}
PageClass.prototype.doSomething = function() {
    alert("DOING SOMETHING");
}

Doing both should enable you to keep your instantiation a bit lighter weight, but still give you some encapsulation. So far, I've never bothered with private vars.

Hylton answered 13/5, 2011 at 15:26 Comment(0)
G
0

If you're using the prototype framework you'll be better off using their way of implementing classes and inheritance. You were probably referring to this article

Usually I don't think private members are used in javascript. (edit: Not in instantiated classes. I see quite regularly some "modules" in our codebase which do hold a private state but could be seen as singletons)

Kevin's answer pretty much sums it up. It is technically possible to work around the language's lack of encapsulation, but it comes at a cost if your class is going to be instantiated a lot. Also I think you'd need some work to get a protected visibility if you're going to use inheritance.

I don't think I saw any private stuff when looking at the ext sources for example. They do put "//private" over methods that should be private, which is a hint that they shouldn't be called directly. It does mean that you need more "discipline" to write getters/setters if you're going to code this way.

Groat answered 13/5, 2011 at 16:3 Comment(0)
E
0

Why yes there is ... now.

The answers above are correct for their time.

Here is the new solution:

'use strict';

// Declare our class
class Metadata {

    // Declare the constructor and pass it some values - a and b are "defaults"
    constructor( ninfo, a = 1.0, b = 1.0 )
    {
        // Set our class variables
        this.ninfo = ninfo;
        this.a = a;
        this.b = b;

        // Define our "secret" or nonenumerable options
        Object.defineProperty( this, 'addA', {
            enumerable: false,
            writable: false,

            // Have it add our passed in value
            value: n => this.a += n
        } );
    }
}

// Call our class and pass in some variables
let x = new Metadata( "we have a and b", 1.0 );

// Log our result if we call "addA"
console.log( x.addA( 3 ) ); // => 4

// Log our object
console.log( x ); // => Metadata { ninfo: 'we have a and b', a: 4, b: 2 }

// Log our object 'for real'
console.log( require( 'util' ).inspect( x, { showHidden: true, depth: null } ) );

// result
// Metadata {
//      ninfo: 'we have a and b',
//      a: 4,
//      b: 2,
//      [addA]: { [Function: value] [length]: 1, [name]: 'value' } }
Enrage answered 27/10, 2016 at 12:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.