JavaScript inheritance through prototypes and the properties of objects

I am currently exploring the concept of prototyped inheritance in JavaScript for a function. This process is well documented in Wikipedia's javascript article. It functions smoothly when dealing with simple JavaScript types:

function Person() {
    this.age = 0;
    this.location = {
        x: 0,
        y: 0,
        absolute: false
    };
};

function Employee() {};

Employee.prototype = new Person();
Employee.prototype.celebrate = function () {
    this.age++;
}

var pete = new Employee();
pete.age = 5;
pete.celebrate();
var bob = new Employee();
bob.celebrate();
console.log("bob is " + bob.age + " pete is " + pete.age);

By setting

Employee.prototype = new Person();
, all properties and methods of Person are inherited by Employee, which is a crucial aspect of inheritance.

As expected, the output is: bob is 1 pete is 6

Now, I am experimenting with altering pete's location (after celebrating):

pete.celebrate();
pete.location.absolute=true;

When checking bob's location.absolute, it displays: true. This result is unexpected as I did not modify bob's location and anticipated it to retain the initial value defined in Person, causing issues in my implementation.

Initially, I believed the output should be false. I understand that I may need to clone the location object from the original Person, but I am uncertain about where and how to execute this action. Are there any alternative techniques for handling inheritance effectively?

Answer №1

Creating a new instance of Employee will result in all properties being copied from Person. This forms a shallow copy, causing pete and bob to share the same location object. Unfortunately, finding a satisfactory solution for this issue is challenging. You might consider utilizing a framework or resorting to a workaround like the one shown below:

function Employee() { Person.apply(this); };

This code snippet invokes the Person constructor within the context of the current object.

To delve deeper into this topic, you can refer to the MDC for additional information: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/apply

Answer №2

Avoid executing the Person constructor during inheritance because an Employee should not include a .location property as it is not part of the Person.prototype.

function generateObject( func ){
    function obj(){}
    obj.prototype = func.prototype;
    return new obj;
}

Next:

Employee.prototype = generateObject( Person );

This method of inheritance ensures no unexpected behaviors (like executing constructors).

You should only invoke the parent constructor within the child constructor:

function Employee() {
Person.apply( this, arguments );
}

Answer №3

Encountering a similar problem led me to devise a solution involving the creation of a distinct constructor for the internal object.

function engine(cc, fuel) {
       this.cc = cc; 
       this.fuel = fuel
}

function car(type, model, cc, fuel) {
       this.type = type; 
       this.model = model;
       this.engine = new engine(cc, fuel);
}


var mycar = new car("sedan", "toyota corolla", 1500, "gas");
console.log(mycar.type);
//sedan
console.log(mycar.engine.cc);
//1500

If I had any methods on the prototypes of 'engine' or 'car' constructors, they would still be available. However, I am not deriving the "car" class from the "engine" class in OOP sense. It was simply unnecessary as the "engine" serves as a component of "car".

When it comes to inheritance, I now lean towards utilizing the newer features introduced in ECMAScript 5 such as Object.create and Object.defineProperties. These methods are compatible even with IE9. Prior to that, I followed the 'apply()' method as recommended by Kosta.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Sending arrays in JSON format using Node.js Express (res.json)

I have a code snippet like this: app.get('/orders/:pizzeriaID/:status', async (req, res) => { try { const requestedOrderByPizzeriaID = req.params['pizzeriaID']; const requestedOrderByStatus = req.params['status']; ...

The array contains no elements, yet it is not empty, and when stringified with JSON.stringify, it results

I've been working on developing an event registration page for a school club I'm involved in, but I'm encountering a problem where my program is unable to correctly read the contents of an array and display each item as a ListItem within a L ...

Grab the code snippet from JSFiddle

I apologize for the seemingly simple question, but I have been struggling with it. I tried looking at similar questions, but I couldn't find a solution. Despite copying the code from http://jsfiddle.net/sB49B/21/, I can't seem to get it to work ...

Optimal approach for handling large JSON files

I am in possession of a JSON file containing approximately 500 lines. I am hesitant to simply dump this JSON data into the end of my Node.JS file as it doesn't seem like the most efficient approach. What alternatives or best practices can be recommend ...

Unlock the full potential of integrating external APIs with Next.js

As a newcomer to NextJs, I am facing the task of making calls to an external Python API from my frontend. Upon discovering NextJs's integrated API feature through creating folders in the app directory, namely api/resource/route, I am wondering what th ...

What makes the creation of Javascript objects so flexible and dynamic?

Recently, I've been exploring the concept of creating new objects in JavaScript. It's interesting to note that in JS, every object creation is dynamic. This allows you to create an object and then add properties later on. Even fields created in t ...

What is the best way to display a placeholder instead of the state's value when a page loads?

I'm having trouble displaying the placeholder of an input instead of its state value. When the page loads, it shows an empty select box because the testType state is null initially. How can I make sure that only the placeholder is shown instead of the ...

How to detect changes in Angular 2 using a separate service

Within my AuthService, I store real-time user data and a method for logging in. When the 'Login' button is clicked, the AuthService is called to retrieve updated user data from the server and update the value of 'this.user'. As a resul ...

CakePHP and Legacy Ajax Script Integration

I have an old script that I want to integrate into a cakephp application. The script uses $_POST and I'm not very experienced with this, so I need some assistance with the integration. This is what the script consists of: THE JAVASCRIPT: prototype ...

Utilizing AJAX POST requests from JavaScript to a Rails 4 controller while implementing Strong Parameters

As a newcomer to Rails, I am looking to insert song_id and title received from JavaScript via AJAX POST into a MySQL database. In my JavaScript file: var song_id = "23f4"; var title = "test"; $( document ).ready( function() { jQuery.ajax({ ...

Implementing class toggling in AngularJS with ng-class

Trying to change the class of an element with ng-class <button class="btn"> <i ng-class="{(isAutoScroll()) ? 'icon-autoscroll' : 'icon-autoscroll-disabled'}"></i> </button> isAutoScroll(): $scope.isAutoScrol ...

Implementing a progress loader in percentage by simultaneously running an asynchronous setTimeout counter alongside a Promise.all() operation

I'm encountering a problem running an asynchronous setTimeout counter simultaneously with a Promise.all() handler to display a progress loader in percentage. Here are the specifics: I've developed a Vue application comprised of three components ...

Firebase onSnapshot error when retrieving data from Snapchot

Having trouble with Firebase authentication. Whenever I try to authenticate with Firebase, I encounter this error message: App.js:27 Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'onSnapshot') Here is the code sni ...

What is the best way to eliminate the nesting in this ternary operation?

Object.values(filter).filter(item => (Array.isArray(item) && item.length > 0) || (typeof item === "boolean" && item === true) || (item !== null)).length ? filterIcon : unFilledIcon In this code, I aim to simplify the nested ternary operator and ...

What could be causing my YouTube code to malfunction with certain playlists?

Check out the first jsfiddle playlist here The Alum Songs Playlist is working perfectly, but unfortunately, the same code is not functioning for another playlist ID. View the second jsfiddle playlist here The Medical Animated Playlist is currently not w ...

Storing audio files in Firebase Cloud Database and displaying them in React js + Dealing with an infinite loop problem

Lately, I've been encountering a persistent issue that has proven to be quite challenging. Any assistance would be greatly appreciated. Thank you in advance. The objective is to create a form that allows for the easy addition of new documents to the ...

Warning: data and salt parameters are necessary, please provide them

Issue: I am encountering an error with registering a new user, specifically when using Postman. I'm not sure why this error is occurring only in Postman. Additionally, I am facing proxy problems where requests cannot be proxied from localhost:3000 to ...

Having difficulty in displaying database values in HTML modal using PHP

On my PHP page, I have a setup that displays data based on the fetched id from the URL. Everything is working smoothly, but when I click a button to show a modal with additional information, the modal appears blank. Here is the code snippet I am using: ...

Update of component triggered only upon double click

I'm encountering an issue with my parent component passing products and their filters down to a subcomponent as state. Whenever I add a filter, I have to double click it for the parent component to rerender with the filtered products. I know this is d ...

Storing the Outcome of a mongodb Search in a Variable

I'm encountering an issue where the result of a MongoDB find operation is not being assigned to a variable (specifically, the line var user = db.collection("Users").findOne below), and instead remains undefined. I am aware that the find function retur ...