Hadi Sharifi
Hadi Sharifi

Reputation: 1527

Whats differences between javascript class definition?

As you know JavaScript is a very flexible object-oriented language when it comes to syntax, but my question is which way of defining function in JavaScript is popular?

Did only javascript provide multi way for helps to know some alternatives in order to read other people's code OR multiple way is based on performance reason?

1. Using a function

function Apple (type) {
    this.type = type;
    this.color = "red";
    this.getInfo = getAppleInfo;
    function getAppleInfo() {
        return this.color + ' ' + this.type + ' apple';
    }
}

2. Using object literals

var apple = {
    type: "macintosh",
    color: "red",
    getInfo: function () {
        return this.color + ' ' + this.type + ' apple';
    }
}

3. Singleton using a function

var apple = new function() {
    this.type = "macintosh";
    this.color = "red";
    this.getInfo = function () {
        return this.color + ' ' + this.type + ' apple';
    };
}

Upvotes: 3

Views: 150

Answers (4)

user1115652
user1115652

Reputation:

In brief to your question "which method is popular?" I must say I have seen all sorts of different approaches used in all sorts of combinations in the wild. There is no standard way (with lots of bugs as a consequence).

The reason there is multiple ways is because JS is not an object oriented language. It is an object based scripting language and wasn't meant originally to be used for big scale applications and libraries. It allows you to do something which looks spectacular in 5 lines of code because of the flexible syntax, but becomes a nightmare when big scale robustness and readability is required.

Personally I wrote a JavaScript library which tries to bring a clean and natural syntax to JS like in C++, declarations first, definitions after and which at once allows comfortable use of static, private, protected, virtual etc members in JS.

OoJs can be found on GitHub. This is a basic example of the syntax:

;( function class_Template( namespace )
{
    'use strict'; // recommended

    if( namespace[ "Template" ] ) return    // protect against double inclusions

        namespace.Template = Template
    var Static             = TidBits.OoJs.setupClass( namespace, "Template", "BaseClass" )

    // Static data members, private by default
    //
    Static.privateStaticDM   = 0
    Static.protectedStaticDM = 0
    Static.publicStaticDM    = 0

    Static.Private
    (
          "privateStaticDM"     //< can do for consistency, but private is the default
        ,  privateStaticMethod  //  accesslevel for data members
    )

    Static.Protected
    (
          "protectedStaticDM"
        ,  protectedStaticMethod
    )

    Static.Public
    (
          "publicStaticDM"
        ,  publicStaticMethod
    )

    // constructor
    //
    function Template( parameter )
    {
        // Data members
        //
        this.privateInstanceDM   = parameter
        this.protectedInstanceDM = 0
        this.publicInstanceDM    = 0

        this.Private
        (
              "privateInstanceDM"
            ,  init

            ,  this.Virtual
               (
                    virtualPrivateInstanceMethod
               )
        )

        this.Protected
        (
              "protectedInstanceDM"
            ,  protectedInstanceMethod
        )

        var iFace = this.Public
        (
              "publicInstanceDM"
            ,  publicInstanceMethod
        )

        this.init() // if you have to do something else

        return iFace
    }

    // all your method definitions go here
    //
    function init(){}
    function privateStaticMethod(){}

})( window )

Upvotes: 1

Karl-Andr&#233; Gagnon
Karl-Andr&#233; Gagnon

Reputation: 33870

First of all, I must tell you that i am not a specialist and you may find better (complete) answer on the subject.

Prototype

The big difference between the 3 ways are the prototype. The method 1 [Usin a function] will allow you to bind prototype object that are not shared among other object.

You can add prototype method the Apple object aswell as the Object object. See for example :

//init
Object.prototype.hello = 'Hello';
Apple.prototype.world = ' World';

//Method 1
alert(apple.hello + apple.world); //Hello World

//Method 2
alert(apple.hello + apple.world); //Helloundefined

//Method 3
alert(apple.hello + apple.world); //Helloundefined

Reutilisability

If you want multiple instance of the same object, you'll have a bad time without the first method. As in you example, if you want 2 different apple, you need to copy/paste and change properties (except for the first method).

//Method 1
var macintosh = new Apple('macintosh');

var otherApple = new Apple('Heisenberg')

//Method 2
var macintosh = {
    type: "macintosh",
    color: "red",
    getInfo: function () {
        return this.color + ' ' + this.type + ' apple';
    }
}

var otherApple = {
    type: "I'm not good with apple's name",
    color: "red",
    getInfo: function () {
        return this.color + ' ' + this.type + ' apple';
    }
}

//Method 3
var macintosh = new (function(type) {
    this.type = type;
    this.color = "red";
    this.getInfo = function () {
        return this.color + ' ' + this.type + ' apple';
    };
})('macintosh');

var otherApple = new (function(type) {
    this.type = type;
    this.color = "red";
    this.getInfo = function () {
        return this.color + ' ' + this.type + ' apple';
    };
})('Still not better');

Variable scope

In the method 1 and method 3, you can have local variable. Elements that are not accessible outside the object.

This is kinda useful when you have event handler function inside you object. In those function, you lose the this reference. Lucky, you can save it in a local variable. Take for example timeout and let not cheat with something like .bind():

//Method 2
var apple = {
    getMe : 'YES!',
    setTimer : function(){
        setTimeout(this.goGetHim, 500);
    },
    goGetHim : function(){
        //alert(this.getMe); Do not work
        alert(apple.getMe); //Kinda lame
    }
}

// Method 1, 3
yourinitfn(){
    var self = this
    this.getMe : 'YES!',
        this.setTimer : function(){
            setTimeout(this.goGetHim, 500);
        },
            this.goGetHim : function(){
                alert(self.getMe); //YES!
            }
}

apple.self;//Undefined

Identification

The last thing i could think of is the identification. Basicly, you can easily, with the method #1, know that the object is an apple :

//Method 1
alert(apple instanceof Object); //True
alert(apple instanceof Apple); //True

//Method 2
alert(apple instanceof Object); //True
alert(apple instanceof Apple); //False

//Method 2
alert(apple instanceof Object); //True
alert(apple instanceof Apple); //False

There must be other advantage

If someone could find other advantage on those subject, I would be gratefull :

  • Memory
  • Performance
  • Readability
  • Programming langage compatibility (ex.: Object to PHP via JSON)
  • Other things i can't think of...

Last note

I've never used, and shall never use the singleton function to create an object. I've read somewhere (can't find the reference now) that using new function is a bad practice and a big performance hit. Note that I may be wrong here...

Upvotes: 2

acjay
acjay

Reputation: 36521

Your Options 1 and 3 are essentially the same. Option 1 would need to be called with new in order to create an instance. Option 3 is simply doing that right away. But that's kind of weird, because if there's only going to be one object, you might as well just use Option 2 (object literal).

You are missing another common option, which I guess you could call an object factory. In such a case, you essentially wrap your Option 2 in a function to be able to instantiate multiple copies of the object.

You are also missing any uses of function prototypes, which is important to use when instantiating classes with methods, for performance reasons. For example:

var Apple = function () {
    this.type = "macintosh";
    this.color = "red";
};
Apple.prototype = {
    getInfo: function () {
        return this.color + ' ' + this.type + ' apple';
    }
};

var myApple = new Apple();

In this case, only one copy of the getInfo method exists, whereas in your examples, that method is recreated every time an apple is instantiated. Also, using prototypes gives the ability to take advantage of prototypal inheritance. Somewhat confusingly, there are alternative ways to accomplish this introduced in newer versions of Javascript, but they're ultimately the same.

I would use your Option 2 if I needed an object without any methods or if I was using previously defined functions as my methods (e.g. not creating new function expressions every time the object is instantiated). Otherwise, I'd use a prototype and constructor function.

I recommend reading Reg Braithwaite's Javascript Allongé, which is free online and really gave me a feel for how the Javascript function and object model can be fully utilized.

Upvotes: 0

Bergi
Bergi

Reputation: 664538

  1. Using a function vs
  2. Using object literals

Means that you will need to call it to get an instance:

var apple = new Apple("Macintosh");

It is then quite equal to the object created with the object literal. However, using a constructor function allows us the optimisation of sharing a few values between multiple instances, mostly the methods:

function getInfo() {
    return this.color + ' ' + this.type + ' apple';
}
function Apple (type) {
    this.type = type;
    this.color = "red";
    this.getInfo = getAppleInfo;
}
var apple1 = new Apple("Macintosh"),
    apple2 = new Apple("Golden Delicious");
apple1.getInfo === apple2.getInfo // only one function object!

However, that's what a factory function could do as well by returning object literals. Using new with the constructor function has the additional advantage of the instances sharing their prototype object, from which they inherit properties. We could simplify it to

function Apple (type) {
    this.type = type;
    this.color = "red";
}
Apple.prototype.getInfo = function getInfo() {
    return this.color + ' ' + this.type + ' apple';
};
// now, having
var apple2 = new Apple("Golden Delicious");
apple2.getInfo === Apple.prototype.getInfo // still only one function object
apple2.getInfo() // and we can access it directly on instances without explicitly
                 // having created a property on them!
apple2 instanceof Apple // is also a feature

See Use of 'prototype' vs. 'this' in JavaScript? for more details.

3 Singleton using a function

var apple = new function() {

Never ever use this. It obscures the existence of a constructor function, which allows to construct other non-singleton instances behind your back.

Upvotes: 0

Related Questions