When invoking a native prototype method, consider extending or inheriting object prototypes for added functionality

Recently, I came across a discussion on Inheritance and the prototype chain where it mentioned:

Avoiding bad practice: Extension of native prototypes

One common mis-feature is extending Object.prototype or other built-in prototypes.

This practice, known as monkey patching, violates encapsulation. Even though it's utilized by frameworks like Prototype.js, it's still not advisable to clutter built-in types with extra non-standard functionality.

The only acceptable reason for extending a built-in prototype is to retroactively add features from newer JavaScript engines; for instance, Array.forEach.

In a practical example, I'm working on an Angular service that handles HTTP requests returning a simple object with attributes and two methods, findAll() and findOne(id). I intend to use one method in my ui-router's resolve method only:

resolve: {
    Resource: 'Resource',
    allImages: function(Resource) {
      var images = new Resource('images');
      return images.findAll();
    },
    singleImage: function(Resource) {
      var image = new Resource('images');
      return image.findOne(4);
    }
},

Depending on which method I call, I want to extend or replace the entire instance Resource with another predefined one - Item or Collection - each having its structure and methods for usage in the Controller:

if (allImages.existNext()) allImages.nextPage();

var currentPage = allImages.meta.currentPage,
    collection = allImages.data;

singleImage.url = 'abc';
singleImage.save(); 

The most effective solution I found involves a minimal example unrelated to HTTP requests:

var myApp = angular.module('myApp',[]);

myApp.factory('Animal', Animal);

function Animal() {

    var Cat = function() {
        this.preferredFood = 'fish';
    };

    Cat.prototype.sayMeow = function() {
        console.log('Meow!')
    };

    var Dog = function(name) {
        this.dogName = name;
    };

    Dog.prototype.sayGrr = function() {
        console.log('Grrr!')
    };

    function Animal(age) {
        this.age = age;
    }

    Animal.prototype = {
        makeItCat: function() {},
        makeItDog: function(name) {
           Dog.call(this, name);
           this.__proto__ = Dog.prototype;
        },
    };

    return Animal;
}

Therefore, inside the Controller, I can utilize this as follows:

var Dan = new Animal(7);
Dan.makeItDog('Dan');
Console.log(Dan.age); // outputs "7"
Console.log(Dan.dogName); // outputs "Dan"
Dan.sayGrr(); // outputs "Grrr!"

This implementation functions well as showcased in this jsfiddle.

The Query at Hand:

Am I following correct practices? Is there any risk of disrupting how Object.prototype operates or losing potential performance benefits? Could there be a better approach, such as incorporating angular.extend or possibly abandoning prototype extension altogether and utilizing something like this instead:

var Dog = function(name) {
    this.dogName = name;
    this.sayGrr = function(string) {
      console.log('Grrr!')
    }
};
...
Animal.prototype = {
    makeItCat: function() {},
    makeItDog: function(name) {
      Dog.call(this, name);
    },
};

Answer №1

Perhaps the approach you are taking could be effective. I have some reservations about the way you implemented the factory. Here is a modified version that might be helpful:

To see a functional jsFiddle demo, click here

The following code includes some minor adjustments:

var myApp = angular.module('myApp', []);

myApp.factory('AnimalFactory', AnimalFactory);

function AnimalFactory() {

  // Primary class definition
  var Animal = function(age, fullName) {

    this.age = age;
    this.fullName = fullName;

    this.eat = function() {
      console.log('I am eating');
    };

  };

  // Implementing Dog as a subclass of Animal 
  var Dog = function(age, fullName) {

    // Calling the constructor for Animal
    Animal.call(this, age, fullName);

    // Adding a new method to the object
    this.bark = function() {
      console.log('I am ' + this.fullName + ' and I bark Woof woof');
    };
  };

  // Assigning the prototype of Dog to Animal
  Dog.prototype = Object.create(Animal);

  var Cat = function(age, fullName) {

    // Invoking the animal constructor
    Animal.call(this, age, fullName);

    // Extending the object with a new method
    this.meow = function() {
      console.log('I am ' + this.fullName + ' and I meow');
    };
  };

  // Setting the Cat prototype to Animal
  Cat.prototype = Object.create(Animal);

  function createDog(age, fullName) {
    return new Dog(age, fullName);
  }

  function createCat(age, fullName) {
    return new Cat(age, fullName);
  }

  // Interface provided by the factory for usage
  return {
    createDog: createDog,
    createCat: createCat
  };
}

function MyCtrl($scope, AnimalFactory) {

  var dan = AnimalFactory.createDog(7, 'Dan');
  dan.bark();

  console.log(dan);

  $scope.dan = dan;
}

I believe the revised code offers a neater implementation of prototype inheritance among your classes. Please share your thoughts so we can further refine it.

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

Creating a switch statement that evaluates the id of $(this) element as a case

I have a menu bar with blocks inside a div. I am looking to create a jQuery script that changes the class of surrounding blocks in the menu when hovering over a specific one. My idea is to use a switch statement that checks the ID of $(this) and then modif ...

Verify the presence of plain ASCII text

I need to verify if the file uploaded is in ascii plain text format. Can you suggest a method? $("#my_file").change(function(){ //alert if file is not ascii plain text }); <input type="file" name="my_file" id="my_file" /> ...

Maintain Bullet and Arrow Size with JSSOR Scaling Feature

I am currently utilizing the jssor image slider with jquery and overall, it is functioning well. However, I have encountered an issue when attempting to resize the slider. My goal is to dynamically resize the slider whenever the window width changes. The ...

Utilize the function of express

The following code is not behaving as expected: var express = require('express'); var app = express(); app.use(function(req, res, next) { console.log('first statement'); next(); }, function (req, res, next) { console.log('se ...

Issue with AngularJS: Component controller fails to load upon routing using ngRoute

As a newcomer to AngularJS, I am struggling with the following code snippet: This is the component defined in the JavaScript file provided: angular.module('EasyDocsUBBApp') .component('loginTag', { templateUrl: 'login ...

Discover the proper way to utilize the orderBy function in AngularJS (1.2) to effectively sort data while preventing incomplete entries from moving around

Currently, I am working on implementing basic CRUD operations using AngularJS. Below is the code for the view: <table> <tr ng-repeat=="person in persons | orderBy:lastName"> <td> {{person.firstName}} </ ...

List component in Angular not refreshing after sorting the array in the service

Currently, I am delving into the realm of Angular (version 5+) to enhance my skills by working on a small project. The project involves setting up basic routing functionalities to showcase the ContactList component upon selecting a navigation tab. Addition ...

Alternative method to jQuery's "find" selector

$('.wrapper a').filter('a'); //returns all anchors I am trying to find a way to select all anchor elements using a specific selector. The issue is that the find method only looks at descendants, so I need an alternative solution. Any s ...

A curated collection saved in LocalStorage using React JS

I have implemented a LocalStorage feature to create a favorite list, but it only adds one item each time the page is reloaded. The items are retrieved from a JSON file. For a demonstration of how my code functions, check out this link: const [ storageIte ...

The navbar toggler icon is not displaying

<header class="container"> <div class="container pt-3 col-md-5 col-sm-5 col-xs-6 text-center"> <a href="#" class="site-logo"><img src="#"></a> <button class="navbar-toggler" type="button" data-toggle="collapse" ...

What could be the reason behind an Ajax Auto-Complete feature suddenly malfunctioning when moving to a new page within the same website?

Working on a website featuring an auto-complete search box powered by Ajax, Javascript, and PHP. As the user types into the search box, an ajax request triggers a php file to query a database and return possible results. Everything works smoothly until the ...

How to Add Functionality to Angular Apps Without Defining a Route

One unique aspect of my website is the navigation bar. It appears on some pages but not others, so I've created a controller specifically for it. Here's how the navigation bar markup looks: <html ng-app="myApp"> <head> <title& ...

By checking the active box and completing the fields, the button will be activated

I'm currently working on a form that requires all fields to be filled out and the acceptance checkbox to be checked before the Submit button becomes active. If any entry or the checkbox is subsequently removed, the button should become inactive again. ...

Unable to navigate a simulated scrollbar

As someone who is new to web development, I am embarking on the journey of building a UI Grid that can effectively display a large amount of data. My goal is to implement a scrollbar that allows for horizontal scrolling across approximately 1,000,000 data ...

What changes can I make to my method in order to utilize async/await?

Within my React application, I have implemented a post request to the server using axios: onSubmit = async (results) => { try { const response = await axios.post("http://localhost:8080/simulate/", results); this.setState({results: ...

Seeking to duplicate script for a new table without making any changes to the original script

I am working with two tables that require the capability to dynamically add and delete rows using separate scripts. How can I modify the second script so that it only affects the second table and not the first one? Table: <table id="myTable" class=" t ...

Tips for implementing validations on a table that changes dynamically

I encountered an issue in my code while working on a dynamic form for age with unobtrusive client-side validation. The problem is that the validation is row-wise, but it behaves incorrectly by removing other rows' validations when I change one. Below ...

How to change a POST request to a PUT request using Express and keeping the

In my express app, I have set up two routes like this: router.post('/:date', (req, res) => { // if date exists, redirect to PUT // else add to database }) router.put('/:date', (req, res) => { // update date }) W ...

Displaying JSON data dynamically by iterating through it in a loop

While working with JSON data in a loop, I noticed that the code quality does not meet my expectations. I have a feeling that I might be missing something in my approach. $(function(){ $.getJSON('data.json', function(data){ let content ...

Strange HTML antics

On my website, I encountered an issue when trying to register without entering any information into the required fields. The errors were correctly displayed in this screenshot: However, after inserting random characters into each field and attempting to r ...