Properly implementing prototypal inheritance: best practices

While there are numerous discussions on prototypal inheritance in JavaScript already, I assure you this is not just another lazy copy. Having thoroughly read all existing threads, I've noticed a plethora of syntactic approaches and varying answers which have left me as bewildered as others on this subject!

Here's the gist of my current approach:

My implementation currently looks like this.

var Person = function(name) {
    this.name = name;

    this.greeting = function() {
        alert("Greetings, I am " + name);
    }

}

var bob = new Person("bob");
bob.greeting();

var Woman = function(name) {
    Person.call(this, name);
    this.gender = "female";
}

Woman.prototype = Object.create(Person.prototype);

var brenda = new Woman("brenda");
brenda.greeting();

Person.prototype.eats = true;

alert(brenda.eats);

Although everything seems to be working smoothly so far, I've been advised that it might not be the optimal approach. Specifically, I was suggested to redefine the constructor like so:

Woman.prototype.constructor = Woman;

The suggestion also entails discarding the use of Person.call method within the actual constructor. However, upon considering this alternative, I find myself at a loss when it comes to passing parameters using this new approach. Plus, the question lingers - why should I make the change when what I'm doing is effective?

Am I overlooking something crucial?

Could there be scenarios where my current implementation might lead to unforeseen errors?

Can anyone offer a definitive 'correct' way forward along with the rationale behind it?

Answer №1

It seems that the approach you have taken is widely regarded as the best one. However, it's worth noting that:

Woman.prototype.constructor = Woman;

does not serve the same purpose as Person.call(...). Each of these actions has a distinct role:

  • Invoking the parent constructor within the child constructor ensures proper initialization of the child instance, resembling the use of super() in ES6 or similar languages.

  • On the other hand, setting the constructor property simply restores the original value of Women.prototype.constructor. Neglecting to do so would result in brenda.constructor pointing to Person. While this does not affect how your inheritance functions internally, external code interacting with your object may depend on having the correct value for constructor. For more information, refer to Advantages of setting the "constructor" Property in the "prototype".

Therefore, the recommended course of action is to execute both steps.

Sometimes, the assignment occurs within the Object.create method, which accurately replicates the original properties and characteristics of the property (including non-enumerability):

Woman.prototype = Object.create(Person.prototype, {
  constructor: {value: Woman, writable: true}
});

In my opinion, the introduction of the class keyword in ES6 aimed at simplifying the complexities surrounding constructor functions and prototypes. While understanding these concepts is essential, the adoption of class syntax offers a more streamlined approach to inheritance:

class Woman extends Person { 
  constructor(name) {
    super(name); 
    this.gender = "female";
  }
}

Answer №2

Here is an Object-Oriented Programming approach in JavaScript

var Person = function(name) {
    this.name = name;
}

Person.prototype.greeting = function(){ 
    var newPerson = new Person(this.name);
    alert("Greetings, I am " + name);
    return newPerson;
} 

Person.prototype.toString=function(){ 
    return '[Person "'+this.name+'"]';
} 

Woman.prototype = new Person();

Woman.prototype.constructor=Woman;      

function Woman(name){ 
    this.name=name;
} 

Woman.prototype.toString=function(){ 
    return '[Woman "'+this.name+'"]';
} 

var somePerson = new Person('Mr.');
var myPerson = new Woman('She');
alert('somePerson is '+somePerson);   // results in 'somePerson is [Person "Mr."]' 
alert('myPerson is '+myPerson);             // results in 'myPerson is [Woman "She"]' 

myPerson.greeting();                    // calls a method inherited from Person 

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

Having trouble setting a JavaScript variable with a PHP session variable

In my PHP file, I have a session variable named $_SESSION['SESS_USER_TYPE'] set to a 2-character string. After the PHP script redirects to an HTML file, I need to retrieve this session variable in a JavaScript variable. This is how I am attempti ...

Turn off the autofill option for passwords in Google Chrome

Is there a way to prevent the password autocomplete dropdown from appearing when clicking on the password field? In Chrome Version 61.0.3163.100, none of the solutions seem to be working. Screenshot This issue has been raised many times, but setting autoc ...

Error: An unexpected token '<' was encountered during the React Webpack build process

My ReactJs project is using Webpack4 and @babel/core 7. However, when I attempt to build the project, I encounter the following error in the terminal: ERROR in ./src/views/Pages/Login/Login.js Module build failed (from ./node_modules/babel-loader/lib ...

Exploring methods to retrieve data from the web3 platform through Node.js

Is there a way to retrieve token information such as name, symbol, and decimals using Nodejs in conjunction with web3js? ...

Does one require the express.js framework in order to create a web application using nodeJS?

Exploring the creation of a basic web application using HTML, NodeJS, and Postgres. Can this be achieved without incorporating the ExpressJS framework? Seeking guidance on performing CRUD operations with NodeJs, Javascript, and Postgres sans ExpressJS. G ...

Issue with datepicker functionality not operational for newly added entries in the table

@Scripts.Render("~/bundles/script/vue") <script> var vueApp = new Vue({ el: '#holiday-vue', data: { holidays: @Html.Raw(Json.Encode(Model)), tableHeader: 'Local Holidays', holidayWarning: true, dateWarning: true }, methods: ...

retrieving JSON data within HTML elements

How can I access the JSON values {{u.login}} from HTML instead of just through JavaScript? Currently, I am only able to access them using JS. Is there a way to directly access JSON values in HTML? At the moment, I am getting them as text. Could you please ...

Using Selenium to interact with drop-down lists using div tags instead of select tags

As a newcomer to automated testing using Selenium Web Driver, I am struggling to test drop down lists for the location type without relying on the select command. The element in question is enclosed within a div tag. I attempted sending keys but that meth ...

Image or Surface at the Front for Textural Effect

Looking for a way to add a background image layer on text using JS/CSS. Any solutions available? For example ...

Using Bootstrap tooltips in an Ajax request

While validating a form with tooltip and performing an AJAX call for the backend response along with an alert message, I encountered an issue. The problem was that even when the text was empty, it still validated and proceeded to the AJAX success call. H ...

Top method for patiently awaiting the completion of the .forEach() function

There are times when I find myself waiting for a .forEach() method to complete, especially in functions involving loaders. My current approach involves using the following code: $q.when(array.forEach(function(item){ //perform iteration })).then(func ...

In Angular components, data cannot be updated without refreshing the page when using setInterval()

Here's the Angular component I'm working with: export class UserListComponent implements OnInit, OnDestroy { private _subscriptions: Subscription; private _users: User[] = []; private _clickableUser: boolean = true; constructor( priv ...

The AJAX function triggers repeatedly upon each click

There is a form with two buttons: save & continue and save and exit. Each button has its own id, save_cont and save_exit respectively. When clicking the second button, the ajax action of the first button is triggered as well, preventing the URL redire ...

Trouble with retrieving the key-value pair of an object using V-html in Vuejs

I have a custom-preset.js file containing the following code. I am using this to obtain a dynamic value for the background color of a button. var customPresets; export default customPresets = color => ( { "id": 0, "name": "custom", "htm ...

Utilize the map function to modify elements within a nested data structure

I'm attempting to modify objects within nested map functions. I have an array of objects with nested data. When I try to execute it this way, the structure of the data changes and I end up with an array of arrays. All I really need is to add a "level ...

Vue.js - Launching Modal for Editing Data Entry

I have a list of records with corresponding buttons on the right side, as shown in this image: https://i.sstatic.net/uevzR.jpg Whenever I click on one of these buttons, I want a dialog box to appear containing various input fields such as text inputs, dro ...

Receiving and transmitting messages repeatedly in Discord.JS

Currently, I am developing a simple bot. Interestingly, the bot seems to be responding multiple times to a single command. Here is the code snippet: const Discord = require('discord.js'); var bot = new Discord.Client(); const PREFIX = "+"; var ...

Creating a Dynamic Slideshow on Autopilot

My JavaScript skills are not perfect and I'm feeling a bit lost. I have this code for a slideshow, but I want to make it automatic while also allowing users to navigate between images freely. I'm struggling to figure out how to implement this fun ...

Using SVG sprites from external sources alongside child nodes

I am working on a website that contains multiple SVG icons and an SVG logo that need to be animated. To improve readability, I have implemented a sprite system using an external file. For loading the sprites, I am utilizing XMLHttpRequests at the start o ...

Strange behavior of for loops in Node.js

Currently, I am immersed in a project for my internship where the back-end utilizes node.js and mongoDB. However, this combination is proving to be less than ideal because our data structure is relational and mongoDB is not optimized for that. The challen ...