Search code examples
javascriptfunctionoopobjectprocedural-programming

What is a good example that shows the difference between OOP and procedural programming in JavaScript?


I can't get my head around OOP in JavaScript.

Many years ago, I used to dabble in programming BASIC and learned a bit of COBOL and FORTRAN in school so I am somewhat familiar with procedural programming, but I never learned any of these to a very high level of proficiency or complexity. I've also done a few hackey things with JS but I guess it was mostly procedural in nature rather than OOP.

Recently, I've decided to train myself to become a web developer and learn JavaScript properly, and based on the rave reviews, I decided on Head First JavaScript Programming as my textbook.

The problem I am having is that I can't figure out how or why using objects is really any different or better than using functions and variables. I've looked around at a ton of tutorials and videos but they all say the exact same thing as the book. "Objects are useful because they are analogous to everyday items in real life such as a car. A car has a model year, a make, a weight, a color, etc... A car can also do things such as start, stop, go, etc. They are functions inside the object and called 'methods'." and that is followed by "this is how to create an object:"

var myCar = {
    make: "Chevy";
    year: 2004;
    kilograms: 2000;
    color: "blue";
    go: function() {
        alert("go!");
    }
};

Great. Now I know that objects are somehow analogous to real life things and I know how to make one with properties and methods. I get that.

And I can access these property values by calling them as follows:

a = myCar.make;
b = myCar.year;
c = myCar.color;

I can also call the function (or method):

myCar.go();

Wonderful. But I STILL can't figure out WHY I want to do it this way. Why is this better than the following?

myCarMake = "Chevy";
myCarYear = 2004;
myCarKgs = 2000;
myCarColor = "blue";

function go() {
    alert("go!");
};

Other than how the code is organized, I don't understand how it's any less procedural. Statements are executed in order, after all. And I don't see what the advantages are to doing all of this.

I keep thinking that what I really need in order to understand this is to see two programs that do the same thing, one coded procedurally with normal variables and functions, and the second one programmed with OO in order to see the difference and how these objects interact with each other in an advantageous way.

I find that all the textbooks and websites that I have found never explain how similar things behave differently or why one is better than the other and there are few if any examples of how to tie it all together well. Most books and tutorials just tell you what you can do but not why you'd want to do that or choose one way over an other. (Irrelevant to this question but another thing I'm wonder about is, I know I can assign a function to a variable but WHY would I want to do that?)

To be clear about what I am looking for, my question is, can someone show me a program that is programmed both ways (both do the same thing and are simple enough for a beginner but complex enough to show why OOP might be needed or advantageous) to highlight the differences and explain why it's better?


Solution

  • In practice, if you have a small script or application, you will not see the difference. But once you move towards larger applications and bigger code bases, you'll see that OOP works much better than PP.

    Here are some high-level advantages of the OOP approach over the PP:

    1) Modularity and maintainability

    The code becomes modular, the related data and methods are packaged into objects.

    This makes it much easier to keep the code under control. It is complex to see this on few lines of code, but as your code grows, the procedural code most often turns into a mess.

    With OOP your code is naturally splitted into smaller parts (objects) and even as the codebase grows, it is still easy to keep the code in order. The modularity leads to better maintainability - it is easier to modify and maintain the code.

    2) Flexibility

    It is much easier to replace the part of the code with some different functionality.

    For example, you can have the Logger object which writes logs to files. But then you decide to write logs to the database instead.

    With PP approach you would need to go over the whole code base searching for something like log_to_file(message, file_name) and replace with something like log_to_db(message, db, table_name).

    With OOP you just create the new DbLogger and "plug it" into the system instead of the previous file logger, so the code which logs data will still look the same, like logger->log(message). Even better, you can decide on the type of the logger run-time, for example, read the setting from the configuration file and create whether file logger or db logger.

    3) Testability

    With OOP it is much easier to take our part of the code (object) and test it alone. If it depends on other objects, these can be replaced with fake implementations (test mocks), so you can really test the piece of code alone.

    Just to demonstrate the difference, let's imagine that instead of one car, you now have three (also the go method should really do something with the variables, otherwise it doesn't make much sense):

    var myCarMake = "Chevy";
    var myCarYear = 2004;
    var myCarKgs = 2000;
    var myCarColor = "blue";
    
    var yourCarMake = "Ford";
    var yourCarYear = 2001;
    var yourCarKgs = 1990;
    var yourCarColor = "white";
    
    var hisCarMake = "Ferrari";
    var hisCarYear = 2011;
    var hisCarKgs = 2990;
    var hisCarColor = "red";
    
    function go(make, year, kgs, color) {
        alert(make + " " + kgs + " " + year + " " color);
    };
    
    go(myCarMake, myCarYear, myCarKgs, myCarColor);
    go(yourCarMake, yourCarYear, yourCarKgs, myCarColor);
    go(hisCarMake, hisCarKgs, hisCarKgs, hisCarColor);
    

    Notice some of the properties of this code:

    • busness-logic code (the definition of car properties and the go method) is mixed with the client code (the part where we call go), we can not separate them, because client code refers to the global variables we created (like myCarMake)
    • many repetitions (like CarMake is written 6 times) and it looks messy
    • easy to make the error (there are errors in last two calls)
    • hard to maintain - if we add a new parameter for the car, we will have to go over all the code base

    Now the version with object (to simplify the code, I keep it as a simple object and separate constructor function, see this for other ways to define the object):

    var CarPrototype = { // empty object-prototype
        make: "",
        year: 0,
        kilograms: 0,
        color: "",
        go: function() {
            alert(this.make + " " + this.kgs + " " + this.year + " " this.color);
        }
    };
    
    // function that constructs the new object
    function createCar(make, kgs, year, color) {
        var car = Object.create(CarPrototype);
        car.make = make;
        car.kgs = kgs;
        car.year = year;
        car.color = color;
        return car;
    }
    
    var myCar = createCar("Chevy", 2004, 2000, "blue");
    var yourCar = createCar("Ford", 2001, 1990, "white");
    var hisCar = createCar("Ferrari", 2011, 2990, "red");
    
    myCar.go();
    yourCar.go();
    hisCar.go();
    

    And some properties of this code:

    • the business logic is clearly defined and separated from the client code, client code is not aware of internal structure of the car object
    • less repetitions and in general the code looks clearer
    • once the object is defined, it is really complex to make the error (you just do myCar->go(), no parameters passing, no chance to mix them or pass in the wrong order
    • easier to modify (if we add a new property for the car, the myCar.go() calls in client code don't need to be changed)

    For sure, I didn't mention all the reasons to use OOP over PP, but I know this from practice - try to spend some time learning OOP principles and start using it and you'll see the huge improvement in code structure. You will make mistakes and do things wrong in the beginning, but the result will anyway be better than procedural code.

    The general approach here is more important than specific language constructs, you can use same principles in C (which is not an OOP language) and in javascript (which has a specific OOP support) as well as in other languages.

    I don't know a resource which compares PP and OOP side by side, but I think you don't really need it. Just look at examples of OOP applications and imagine how these would look like if written in procedural style.

    My favorite book about OOP is Design Patterns, it demonstrates how elegant and powerful can be interaction between objects. Probably, you will also need to find something where basic OOP concepts are explained (already mentioned encapsulation, polymorphism, inheritance) and principles (most notably SOLID).