{"id":24364130,"url":"https://github.com/nmhq/oop-in-javascript","last_synced_at":"2025-04-15T17:47:56.283Z","repository":{"id":203582279,"uuid":"410460952","full_name":"nmhq/OOP-in-JavaScript","owner":"nmhq","description":"Learn and Understand OOP in JavaScript 🤔","archived":false,"fork":false,"pushed_at":"2023-10-26T06:41:26.000Z","size":15,"stargazers_count":6,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-28T23:11:20.342Z","etag":null,"topics":["constructor-functions","javascript","oop","prototypal-inheritance","prototypes"],"latest_commit_sha":null,"homepage":"","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nmhq.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-09-26T05:41:33.000Z","updated_at":"2024-08-30T16:53:46.000Z","dependencies_parsed_at":null,"dependency_job_id":"c0b521dc-4755-4718-80a0-b799a67d6e8c","html_url":"https://github.com/nmhq/OOP-in-JavaScript","commit_stats":null,"previous_names":["naimulcsx/oop-in-javascript","nmhq/oop-in-javascript"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nmhq%2FOOP-in-JavaScript","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nmhq%2FOOP-in-JavaScript/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nmhq%2FOOP-in-JavaScript/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nmhq%2FOOP-in-JavaScript/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nmhq","download_url":"https://codeload.github.com/nmhq/OOP-in-JavaScript/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249124766,"owners_count":21216696,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["constructor-functions","javascript","oop","prototypal-inheritance","prototypes"],"created_at":"2025-01-18T23:21:05.080Z","updated_at":"2025-04-15T17:47:56.050Z","avatar_url":"https://github.com/nmhq.png","language":null,"readme":"# Object-Oriented Programming in JavaScript\n\nYou are not the only one to feel that JavaScript is weird. This is very common for people coming from other backgrounds. That's because JavaScript is not like those traditional class based languages.\n\n## History\n\nIt is important to know the historical context around JavaScript's creation. In 1994 Netscape relased their web browser called Netscape navigator. The web browser was a major success. Brendan Eich convinced his boss at Netscape that the Navigator browser should have its own scripting language. At that time Java was very very popular. Netscape was negotiating with Sun to include it in Navigator. The big debate inside Netscape therefore became “why two languages? why not just Java?”.\n\nThey eventually decided to come up with a new language for their browser. But the diktat from upper engineering management was that the language must look like Java beceause they wanted to attract Java programmers. At the same time, they didn't want to compete with Java. So Brendan Eich did something different for JavaScript. He chose first-class functions from [Scheme](\u003chttps://en.wikipedia.org/wiki/Scheme_(programming_language)\u003e) and prototypes from [Self](\u003chttps://en.wikipedia.org/wiki/Self_(programming_language)\u003e) as the main ingredients.\n\n## What is an Object?\n\nIn order to understand OOP in JavaScript, it’s important to understand the concept of objects. They are a primary part of JavaScript. Almost everything in JavaScript is an object.\n\n\u003e An object in JavaScript is simply a key-value pair where key is a string and the value can be anything.\n\nIt's simillar to a data structure called hash table. However, the implementation can vary on different JavaScript engines. The term Object can be confusing as we often associate it with classes in other language. In traditional OOP languages, you can't create objects without classes. In JavaScript, objects can be created on the fly without the need of classes.\n\n### Creating objects in JavaScript\n\nJust like we can create variables, we can create objects on the fly. An object  can be created in serveral ways. In the examples, we'll try to model an Object for a person. We'll have the following properties and methods in the object.\n\n- `firstName` - first name of the person\n- `lastName` - last name of the person\n- `age` - age of the person\n- `greet()` - method to greet a person\n- `getFullName()` - method to get full name of the person\n- `isAdult()` - method to to check if the person is a legal adult\n\n#### Object Literals\n\nLet's start with object literals. With the object literals syntax, you can create objects just with a set of curley braces - {}.\n\n```js\nconst person = {\n    firstName: \"Naimul\",\n    lastName: \"Haque\",\n    age: 26,\n    getFullName: function () {\n        return `${this.firstName} ${this.lastName}`;\n    },\n    isAdult: function() {\n        return this.age \u003e= 18;\n    },\n    greet: function() {\n        console.log(`Hello, my name is ${this.getFullName()}`);\n    }\n};\n```\n\n#### Using `new Object()`\n\nIn JavaScript, the `new Object()` statement is used to create a new instance of the Object constructor. This essentially creates an empty object. It's equivalent to creating an empty object using object literal notation {}.\n\n```js\nconst person = new Object(); \n\nperson.firstName = \"Naimul\";\nperson.lastName = \"Haque\";\nperson.age = 26;\nperson.getFullName = function () {\n    return `${this.firstName} ${this.lastName}`;\n};\nperson.isAdult = function() {\n    return this.age \u003e= 18;\n}\nperson.greet = function() {\n    console.log(`Hello, my name is ${this.getFullName()}`);\n}\n```\n\n#### Using `Object.create()`\n\nThe previous 2 methods of creating objects were somewhat regular. `Object.create()` creates a new object and returns the empty object, additionally it does one very important thing. We'll come back to it shortly.\n\n```js\n// ignore the null value we're passing into Object.create()\n// we'll explain this shortly but anyway this creates an empty object\nconst person = Object.create(null);\n\nperson.firstName = \"Naimul\";\nperson.lastName = \"Haque\";\nperson.age = 26;\nperson.getFullName = function () {\n    return `${this.firstName} ${this.lastName}`;\n};\nperson.isAdult = function() {\n    return this.age \u003e= 18;\n}\nperson.greet = function() {\n    console.log(`Hello, my name is ${this.getFullName()}`);\n}\n```\n\n### Issues in the previous 3 approaches\n\nLet's first take a look at the issues that we have with the above 3 approaches we've described so far. Think about it, if we want to define more person, we have to repeat the same codes which is not a good practice. \n\nSo what can we do here? Simple, we can create a reusable function, that will create and return these person objects for us.\n\n```js\nfunction createPerson(firstName, lastName, age) {\n    const person = {};\n    person.firstName = firstName;\n    person.lastName = lastName;\n    person.age = age;\n    person.getFullName = function () {\n        return `${this.firstName} ${this.lastName}`;\n    };\n    person.isAdult = function() {\n        return this.age \u003e= 18;\n    }\n    person.greet = function() {\n        console.log(`Hello, my name is ${this.getFullName()}`);\n    }\n    return user;\n}\nconst person1 = createPerson(\"Naimul\", \"Haque\", 26);\nconst person2 = createPerson(\"John\", \"Doe\", 32);\n```\n\nWe can create many users with this function. `createPerson()` function is now reusable but it's extremely inefficient. The reason is simple, the common methods `getFullName()`, `isAdult()` and `greet()` are created on the person object everytime we create a new person. These methods are common functionality and doesn't need to have it's own copy for each object. We need some way to somehow share the common functionality.\n\n### Sharing common functionalities\n\n```js\nfunction createPerson(firstName, lastName, age) {\n    const person = {};\n    person.firstName = firstName;\n    person.lastName = lastName;\n    person.age = age;\n    return person;\n}\n\n// this is the object consisting of the methods that we want\n// to share with all the persons created by the createPerson()\n// function without creating a copy for each individual object\nconst commonMethods = {\n    getFullName() {\n        return `${this.firstName} ${this.lastName}`;\n    },\n    isAdult() {\n        return this.age \u003e= 18;\n    },\n    greet() {\n        console.log(`Hello, my name is ${this.getFullName()}`);\n    }\n};\n```\n\nWe've moved all the methods to another object. It's obvious that the `person` object doesn't know where to find the common methods. So, we need to somehow say to the person object that whenever you need a method, take a look at the `commonMethods` objects. The question is how do we do that?\n\n#### Introducing prototypes and `__proto__`\n\n`prototypes` are JavaScript's way to achieve inheritance. prototypes are a way by which JavaScript objects can inherit features from one another.\n\nEvery object in JavaScript gets a special propertly called `__proto__`. Suppose we want to store `user.isMarried` in a variable. The property doesn't exist on the person object. So instead of giving up, JavaScript will try to find it in `__proto__`. So anything if JavaScript is unable to find some property or method in the actual object, it will look into the special property called `__proto__`. \n\nSo that basically means if we can set `__proto__` of each `person` object to be the `commonMethods` object, our job is done. How do we do that? Remember `Object.create()`? It returns a new object, but the additional thing it does is, it sets the `__proto__` of that object to be the object that we pass into this as argument.\n\n```js\nfunction createPerson(firstName, lastName, age) {\n    // it creates a new object called person and sets\n    // the person object's __proto__ to be the commonMethods\n    const person = Object.create(commonMethods);\n\n    person.firstName = firstName;\n    person.lastName = lastName;\n    person.age = age;\n\n    return person;\n}\n\nconst commonMethods = {\n    getFullName() {\n        return `${this.firstName} ${this.lastName}`;\n    },\n    isAdult() {\n        return this.age \u003e= 18;\n    },\n    greet() {\n        console.log(`Hello, my name is ${this.getFullName()}`);\n    }\n};\n```\n\nYou might be thinking, this is simillar to how a `class` creates an object in other programming languages. Don't we have the `class` keyword in JavaScript? Yes, we have the `class` keyword, and we'll get there eventually. The reason I'm showing you all these in details is because, `class` is just a syntantic sugar in JavaScript. Even if you write classes, it's cruitial to understand. the underlying concepts.\n\nNow, this solution definitly works, but its a bit declarative. We are handcrafting everything like creating objects with a different `__proto__`. Now JavaScript gives us a way to automate these stuffs with the `new` keyword.\n\n### Functions are Objects\n\nBefore we learn about the `new` keyword, we need to understand that functions are objects behind the scene. We can attach properties to functions. The following code looks a bit strange but it is indeed valid in JavaScript.\n\n```js\nfunction sum(a, b) {\n  return a + b;\n}\n\nsum.myName = \"Naimul Haque\";\nconsole.log(sum.myName);\n```\n\n### Constructor Functions\n\nIn JavaScript, a constructor function is a special type of function that is used to create and initialize objects. The constructor function is used with the `new` keyword to create instances of objects simillar to how we use classes in other programming languages. Let's try to model a `person` with constructor functions.\n\n```js\nfunction Person(firstName, lastName, age) {\n    this.firstName = firstName;\n    this.lastName = lastName;\n    this.age = age;\n}\n\n// create an instance of the Person\nconst person1 = new Person(\"Naimul\", \"Haque\", 26);\n```\n\nThe function `Person` is our constructor function, and when we use the `new` keyword in front of it, it will create an instance everytime we do that.\n\n#### The `new` keyword\n\nThe previous code example might be confusing for a lot of people, specially if you try to compare it with other languges. Where does the `this` comes from? What is the value of `this`? How does the person getting returned from the function? We'll all the answers, when we take a look at how the `new` keyword works in JavaScript.\n\n- Creates a new empty object.\n- Sets the object's prototype (`__proto__`) to be the function's prototype.\n- Invokes the constructor function where `this` refers to the empty object that it created.\n- Implicitly returns the object\n\nThis is how, the instances are getting created from the Person constructor functions. It's fine if you are not getting the second step in the list, we'll describe it in a moment.\n\n#### Prototype of a Constructor Function\n\nWe saw functions are objects. Constructor functions can have a special property called `prototype`. It's an object and when we attach any property to this `prototype` object, the `new` keyword will use this to set the object's `__proto__` to be the constructor function's `prototype`.\n\n```js\nfunction Person(firstName, lastName, age) {\n    this.firstName = firstName;\n    this.lastName = lastName;\n    this.age = age;\n}\n\nPerson.prototype = {\n    getFullName() {\n        return `${this.firstName} ${this.lastName}`;\n    },\n    isAdult() {\n        return this.age \u003e= 18;\n    },\n    greet() {\n        console.log(`Hello, my name is ${this.getFullName()}`);\n    }\n};\n\n// create an instance of the Person\nconst person1 = new Person(\"Naimul\", \"Haque\", 26);\n```\n\nNow, each time we create a Person instance, the object's `__proto__` will refer to the `Person.prototype`. We can validate the statement with the following code.\n\n```js\nperson1.__proto__ === Person.prototype // true\n```\n\n### ES6 Classes\n\nThere were not `class` keyword in JavaScript before ES6. The ES6 brings the `class` keyword that everyone is familiar with. It's just a syntatic sugar over the already existing way for creating objects with `constructor functions` or `Object.create()`.\n\n```js\nclass Person {\n  constructor(firstName, lastName, age) {\n    this.firstName = firstName;\n    this.lastName = lastName;\n    this.age = age;\n  }\n\n  getFullName() {\n    return `${this.firstName} ${this.lastName}`;\n  }\n\n  isAdult() {\n    return this.age \u003e= 18;\n  }\n\n  greet() {\n    console.log(`Hello, my name is ${this.getFullName()}`);\n  }\n}\n\n// Create an instance of the Person class\nconst person1 = new Person(\"Naimul\", \"Haque\", 26);\n```\n\n### Resources\n\n[Performance of key lookup in JavaScript](https://stackoverflow.com/questions/7700987/performance-of-key-lookup-in-javascript-object)\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnmhq%2Foop-in-javascript","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnmhq%2Foop-in-javascript","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnmhq%2Foop-in-javascript/lists"}