3

I'm beginning to learn more about writing JS using the Prototype object, but I want to make sure I don't pick up any bad habits from other developers. My understanding of using Prototype is to create public methods for your instance. For example:

var module = new Module();
module.method();

But I see a lot of developers creating all their code inside the Prototype object, things that I would consider "private". Is this bad practice or considered okay? It just means I can then do:

module.privateFn();

Do they know this? Is that okay? Any help appreciated. I've been looking through the source code on GitHub to try establish the best way forward, here's a script that uses Prototypes for everything (for instance attachEvent which they clearly want privately kept):

https://github.com/WickyNilliams/headroom.js/blob/master/dist/headroom.js

Much appreciated, I want to make sure I develop using the correct implementations.

Stephen Jenkins
  • 1,776
  • 3
  • 24
  • 39
  • 1
    See http://stackoverflow.com/questions/4736910/javascript-when-to-use-prototypes – mccainz Dec 09 '13 at 13:56
  • All properties of an JS object are public, there's not really a difference. You put those properties on the prototype which *all instances share*. – Bergi Dec 09 '13 at 16:53

2 Answers2

0

Explaining this with a few words is impossible. A generally good pattern is to construct methods through prototypes when you want to optimize your code. A good guideline is to only put the most essential data in the memory, using prototypes is critical for this since the prototyped variables and methods isn't injected into the memory until you request them.

When it comes yo your example there are no prototypes.

Simple example

// new object
var Dog = function() {
    var that = this;

    // add a property
    that.name = "Fido";

    // add a method
    that.getName = function() {
        return that.name;
    };
};
// ... all the above is stored in memory directly     


// Requires to be constructed
var dogObj = new Dog();
console.log(dogObj.getName()); // Fido

delete Dog.name // false
typeof Dog.name // "string"
delete dogObj.name // true
typeof dogObj.name // "undefined"
typeof Dog.name // "string" (still there)

// Will be available in the dogObj (after you call it)
dog.prototype.first = "first";

// Will be available in the dogObj (after you call it)
dog.prototype.second = function() {
    return "second";
}

// Will not be available in dogObj
dog.third = "third";
Eric Herlitz
  • 25,354
  • 27
  • 113
  • 157
  • Thanks for this. So you're saying that you should create properties/methods from the Obj constructor, and when you want shared/optimised code (sharing the prototype object is fast compared to creating new methods over and over we know). So your answer would be no, use Prototypes only for those public methods? – Stephen Jenkins Dec 09 '13 at 13:33
  • Yeah, you cannot touch private variables and methods in the originating object. – Eric Herlitz Dec 09 '13 at 14:04
0

First of all you don't need to write modules using prototype. Think like if you writing something like a class you should use prototypes. And also it's important to where define your methods. Defining methods on prototype object and defining them in constructor function is totally different things!

Let's see a sample class definition with using methods defined in constructor:

var Dog = (function () {
    var Dog = function (age, name) {
        var that = this;

        this.age = age;
        this.name = name;

        this.sayHi = function () {
            console.log('Warf! Im ' + that.name); // meaning of "this" changed!!!
        };

        this.anotherMethod = function () {};
    };

    return Dog;
}());

var puppy = new Dog(1, 'puppy');   // sayHi and anotherMethod created
var sirius = new Dog(1, 'sirius'); // sayHi and anotherMethod recreated 

sirius.sayHi = function () { console.log('Yohalolop!'); };

puppy.sayHi();  // -> 'Warf! Im puppy'
sirius.sayHi(); // -> 'Yohalolop!'

So there is some problems with the above example, firstly methods are defined like any other instance variables. Actually yeah you define them as instance variable and this means this functions are recreated for every instance object you create. I guess you have mentioned you can't use this keyword in your method definitions. This is error prone and there is a chance to forget that and use this keyword by mistaken. There are some times you can use methods as instance variables of course like variable callbacks.

Let's see a sample class definition with prototype object:

var Dog = (function () {
    var Dog = function (age, name) {
        this.age = age;
        this.name = name;
    };

    // sayHi method defined only once in prototype
    Dog.prototype.sayHi = function () {
        console.log('Warf! Im ' + this.name; // we can use this keyword
    };

    // anotherMethod defined only once in protoype
    Dog.prototype.anotherMethod() {
    };

    return Dog;
}());

var puppy = new Dog(1, 'puppy');   
var sirius = new Dog(1, 'sirius');  // sirius and puppy sharing same prototype object

puppy.sayHi();  // -> 'Warf! Im puppy'
sirius.sayHi(); // -> 'Warf! Im sirius'

// remember puppy and sirius sharing same prototype object
Dog.prototype.sayHi = function () {
    console.log('Yohalolop');
};

puppy.sayHi();  // -> 'Yohalolop'
sirius.sayHi(); // -> 'Yohalolop'

As an answer to your question about private functions, it is more complicated. Yes you can use private functions even you define your methods on prototype, but there are some concerns about testing. Usage of them is up to you. I prefer to don't use. Let me show some examples.

var Calculator = (function () {
    var Calculator = function () {
        this.importantNumber = 2;
    };

    // There is unfortunately no native implementation
    // for private methods but you can mimic them with
    // unaccessible functions and binding.
    var someExtremeComputations = function () {
        return 40 + this.importantNumber; // this keyword points to instance because of binding
    };

    Calculator.prototype.getMeaningOfLife = function () {
        var result = someExtremeComputations.call(this); // we bind function to instance
        return result;
    };

    return Calculator;
}());

This is the one of the examples how you can define private methods in javascript. The problem with private functions, they can't be tested. There is no way to test someExtremeComputations method.

Some people (includes me) use prefixed underscore naming convention for private methods. So they are actually public methods but if someone calling them or overriding they were warned by prefixed underscore. After all we can test private methods since they are public in real.

var Calculator = (function () {
    var Calculator = function () {
        this.importantNumber = 2;
    };

    // private method's name prefixed by an underscore to warn
    // other developers to be careful about that or not to use.
    Calculator.prototype._someExtremeComputations = function () {
        return 40 + this.importantNumber; 
    };

    Calculator.prototype.getMeaningOfLife = function () {
        var result = this.someExtremeComputations(); // no need to bind
        return result;
    };

    return Calculator;
}());
Umur Gedik
  • 477
  • 5
  • 12