Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reason for using `prototype` instead of `this`

Tags:

javascript

I am using Lightbox2

https://github.com/lokesh/lightbox2/blob/master/js/lightbox.js

And I don't understand why all the inner members of Lightbox are prototyped (Lightbox.prototype.init) and not simply members (Lightbox.init)?

If they are specific to each instance of lightbox wouldn't it be easier to use this.init?

like image 351
ilyo Avatar asked Jun 09 '12 10:06

ilyo


2 Answers

Confused? Don't be...

Think of it this way:

  1. Lightbox is your class definition, but it's not yet an instance.

  2. Whatever you put directly on the class is like a static member:

    Lightbox.staticFunc = function() {
        // "this" will not point to instance object
    };
    
  3. Whatever you put on its prototype is a shared instance member:

    Lightbox.prototype.instanceFunc = function() {
        // "this" will point to object instance so members can be accessed
    };
    
  4. When you create an instance of a class, all instance members are accessible throught this keyword, but static ones through class definition:

    var someData = Lightbox.staticFunc();
    var l = new Lightbox();
    l.instanceFunc();
    

Does this clear you understanding of prototype members?

Lightbox code then

The code that you've been looking at means this:

// this is a constructor that accesses instance properties (using "this")
// ------
// since properties are accessed via "this.something" means that they are
//    not shared between instances but are part of one particular instance
// ------
function Lightbox(options) {
    this.options = options;
    this.album = [];
    this.currentImageIndex = void 0;
    this.init();
}

// adding an instance method that will be accessible to lightbox object instance
//    that's why it can also access instance members (using "this")
// ------
// all functions that are defined on the prototype are shared between
//    all instances so they consume less resources because not every
//    object instance created them separately.
// ------
Lightbox.prototype.init = function() {
    this.enable();
    return this.build();
};

But some parts of this code are a bit confusing i.e.

LightboxOptions = (function() {

    function LightboxOptions() {
        this.fileLoadingImage = 'images/loading.gif';
        this.fileCloseImage = 'images/close.png';
        this.resizeDuration = 700;
        this.fadeDuration = 500;
        this.labelImage = "Image";
        this.labelOf = "of";
    }

    return LightboxOptions;

})();

LightboxOptions class is contained within a function closure even though it doesn't define any private data, so the outer immediately executing function could be omitted in this example while having identical results:

LightboxOptions = function() {
    this.fileLoadingImage = 'images/loading.gif';
    this.fileCloseImage = 'images/close.png';
    this.resizeDuration = 700;
    this.fadeDuration = 500;
    this.labelImage = "Image";
    this.labelOf = "of";
};

It would of course be possible to define those functions in a constructor using this but then they wouldn't be shared between instances hence every object instance would define the same function hence consuming more resources. So this is not the same although from the execution point it does look the same:

CustomClass = function() {
    this.prop = true;
};
CustomClass.prototype.method = function() { alert("I'm shared."); };

is slightly different than:

CustomClass = function() {
    this.prop = true;
    this.method = function() { alert("I'm duplicated in every instance."); };
};

The later consumes more resources while function is defined for every object instance.

...and a bit more to completely clear this thing

Suppose we have this class definition:

var C = function() {
    this.prop = true;
    this.method = function() { console.log("Per instance method"); };
}
C.prototype.method = function() { console.log("Shared instance method"); };

What happens here if we call these lines of code

var a = new C();
var b = new C();
a.method();
b.method();
delete a.method;
a.method();
b.method();

What do you think the output would be? You should get at least a little confused what happens after delete? Which method will get deleted? Per instance? Shared? Both? Well as it should be per instance method gets deleted on object instance a, that's why afterwards it reports that the shared method has been called. But only on a. b still has its own per instance method.

So without any further ado, output looks like this:

Per instance method      // a.method
Per instance method      // b.method
Shared instance method   // a.method
Per instance method      // b.method

What about prototype properties

These are different. When you create an object instance all those properties get copied to every object and are not shared. So whatever you do on them within the realm of a particular object will not get reflected to others.

If you'd then delete such property on a particular object it would still be available with its initial value as it was when object got instantiated.

var C = new function() {};
C.prototype.prop = 1;

var a = new C();
var b = new C();

a.prop = 10;   // does not change the value of "b.prop"
delete a.prop; // "a.prop" is now back to 1
like image 82
Robert Koritnik Avatar answered Nov 16 '22 03:11

Robert Koritnik


If they are specific to each instance of lightbox wouldn't it be easier to use this.init?

They shouldn't be that's why they are putting everything in prototype object. When you use prototype, all methods still become available to you only that they do not become instance members.

JavaScript works with prototype chain, when it sees a method, it searches through the prototype chain till it finds the specified method. This process goes till the final Object object if not found in the middle.

You should only create instance members (via this) that you think are reasonable or needed because it adds an overhead (computational waste) if you put unnecessary methods using this keyword eg instance members.

like image 4
Sarfraz Avatar answered Nov 16 '22 03:11

Sarfraz