Copying an instance in JavaScript - The copy method

Is there a way to easily duplicate all properties and methods of a class instance?

class A {
    get prop1() { return 1; }
    get prop2() { return 2; }

    doStuff() {
        return this.prop1 + this.prop2;
    }
}

class B extends A {
   get prop1() { return 5; }
}
class AWrapper {
    constructor(a) {
        // [1] Duplicate all methods/properties of a
        this.doStuff = () => a.doStuff() + 42;
    }
}

const a = new A();
const b = new B();
const wA = new AWrapper(a);
const wB = new AWrapper(b);
console.log(a.prop1(), wA.prop1(), wB.prop1()); // 1, 1, 5
console.log(a.doStuff(), wA.doStuff()); // 3, 45

Instead of manually copying each method/property like in [1], is there a simple command to achieve this so that wA mirrors the structure of a?

Answer №1

Typically, the Proxy object is commonly used when dealing with mixins or decorators:

class X {
    get data1() {
        return 'apple';
    }

    get data2() {
        return 'banana';
    }

    processData() {
        return this.data1 + this.data2;
    }
}


class Y extends X {
    get data1() {
        return 'orange';
    }
}


function applyDecoration(target) {
    let mixin = {
        processData() {
            return target.processData() + ' and cherry';
        }
    }

    return new Proxy(target, {
        get(_, prop) {
            return (prop in mixin) ? mixin[prop] : target[prop];
        }
    });
}


const x = new X();
const y = new Y();

const wX = applyDecoration(x)
const wY = applyDecoration(y)

console.log(x.data1, wX.data1, wY.data1); // 'apple', 'apple', 'orange'
console.log(x.processData(), wX.processData()); // 'applebanana', 'applebanana and cherry'

Answer №2

Learn how to utilize the extends keyword and invoke the parent class's (A) doStuff method with:

this.doStuff = () => super.doStuff() + 42;

class A {
  get prop1() { return 1; }
  get prop2() { return 2; }

  doStuff() {
      return this.prop1 + this.prop2;
  }
}

class AWrapper extends A {
  constructor(...args) {
    super(...args);
      this.doStuff = () => super.doStuff() + 42;
  }
}

const a = new A();
const w = new AWrapper(a);

console.log(a.prop1, w.prop1); // 1, 1
console.log(a.doStuff(), w.doStuff()); // 3, 45

Answer №3

Check out the solution below.

class B {
    get prop1() { return 3; }
    get prop2() { return 4; }

    manipulateData() {
        return this.prop1 + this.prop2;
    }
}
class BWrapper extends B{
    constructor(b) {
        super(b);
        this.manipulateData = () => b.manipulateData() + 42;
    }
}
const b = new B();
const wB = new BWrapper(b);
const wC = new BWrapper(b);
console.log(b.prop1, wB.prop1, wC.prop1); // 3, 3, 3
console.log(b.manipulateData(), wB.manipulateData()); // 7, 46

Answer №4

To successfully implement the code, it is essential to create a new BWrapper class in addition to utilizing the extends and super keywords within the existing classes:

class X {
  get value1() {
    return 10;
  }
  get value2() {
    return 20;
  }

  processData() {
    return this.value1 + this.value2;
  }
}

class Y extends X {
  get value1() {
    return 50;
  }
}

class XWrapper extends X {
  constructor(x) {
    super();
    this.processData = () => x.processData() + 100;
  }
}

class YWrapper extends Y {
  constructor(y) {
    super();
    this.processData = () => y.processData() + 100;
  }
}

const x = new X();
const y = new Y();
const wrapperX = new XWrapper(x);
const wrapperY = new YWrapper(y);
console.log(x.value1, wrapperX.value1, wrapperY.value1); // 10, 10, 50
console.log(x.processData(x), wrapperX.processData(wrapperX)); // 30, 40

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

How can one efficiently make API requests using Vuex?

Being new to both Vue Webpack and Vuex after transitioning from the Ember world, I have set up my Vue Webpack app with Vuex using vue-resource in two different files: /src/store/api.js import Vue from 'vue'; import { store } from './store& ...

Looking for assistance in creating a unique jQuery validation function tailored to your

Looking at my form attribute, it appears as follows: onsubmit="return validateForm(this);" Additionally, I have a jQuery function set up like this: function validateForm(form) { $(form,"input").each(function() { if($(this).length < 1) { ...

Acquiring the index of a selector event within a list of dynamic elements

I am seeking guidance on how to go about solving the issue of obtaining an event index. I have a hunch that closures might play a role in the solution and would appreciate some insights. Initially, I dynamically build an HTML5 video container using an aja ...

Accordion feature exclusively toggles the initial item

I am having an issue with the code in my index.php file. Only the first item in the accordion menu is showing up correctly. When I click on "Status" or "Repeated", I expect to see the sub-menu of the clicked item, but instead, I am getting the result from ...

Accessing nested objects within a JavaScript array for an Express API

My current data sample looks like this: var data = [{ articles : [{ id : '0', url : 'foo', title : 'Foo', body : 'some foo bar', category : 'foo', tags : ...

Exploring techniques for creating realistic dimensions in CSS

My goal is to create a responsive website that accurately displays an object with specified dimensions, such as a width of 100mm, regardless of the user's screen resolution. However, I am facing challenges in achieving this consistency across all devi ...

Update the div content to completely replace it with fresh data using Ajax

I'm currently working on implementing a currency switcher feature for my website, allowing users to toggle between two different currencies. The site is a reservation platform with a booking form displayed on the left side and the booking details occu ...

Unforeseen Problem: Mocha ES6 Node App Glitch

Encountering an ES6 import issue in Mocha test cases currently. Even after attempting to add the latest Babel and presets, the issue remains unresolved. Various solutions have been tested but none seem to fix the problem. This snippet shows my package.jso ...

Next.js is causing me some trouble by adding an unnecessary top margin in my index.js file

I started a new project using next.js by running the command: yarn create next-app However, I noticed that all heading and paragraph tags in my code have default top margins in next.js. index.js import React, { Component } from "react"; import ...

Determine the percentage of payments, similar to Upwork, by leveraging the power

Currently, I am working on developing a percentage calculation similar to what is seen on the Upwork website. The calculation appears to be accurate when derived from the base amount at a rate of 10%. For instance, if we take a base amount of 89.00, the ...

The current date is cycling back to the month before

There is a datetime received from my api as 2018-09-01T00:00:00.000Z, referred to as frame.scandate. Another date is generated within the program as 2018-09, simply known as scandate. These examples can represent any year/month combination. In my code: ...

How can we incorporate SaxonJS higher-order functions into the Node.js runtime, separate from JS/HTML?

We are currently in the process of transitioning an older C# system that relied on custom functions to enhance XSLT processing. Our plan is to convert it to Node.js/saxon-js. After reviewing the documentation, it appears that while higher order functions ...

Exploring the power of Partial Views in ASP.NET MVC 4 with Ajax.ActionLink

On my homepage, I am attempting to incorporate links that will render partial views - revealing information from the database when clicked. I want the link to be replaced by text on the same page. Despite following a tutorial, I am facing challenges in get ...

Error thrown: SyntaxError - Forbidden break statement in AJAX code execution

Trying to exit a loop nested within a statement has been a challenge. Despite researching similar questions on stackoverflow, I have not found a solution that works. Below is the current code in question: for (var i = 0; (i < 10); i++) { ...

Dealing with checked input type='checkbox' in React - A guide

Having a set of checkboxes, some already checked and some to be updated by the user. The issue here is that while the checkboxes render correctly initially, they do not change upon clicking. The 'checked' value does get updated when onChange is t ...

Managing numerous JavaScript objects within a plugin

I have developed a straightforward javascript plugin that enables me to gather data from specific html elements. A page can contain x number of elements (usually up to 20), each with its own settings. However, the issue I am facing is that the returned obj ...

extracting data from a javascript array

While facing an issue with scraping a website , I received helpful solutions from Fatherstorm and marcog. Despite the great solution provided by Fatherstorm, there were some minor bugs related to start time and the number of image sources being retrieved a ...

The body parser is preventing the NODE from loading on localhost

var express = require('express'); var app = express(); var bodyParser = require('body-parser'); //ISSUE LINE **app.use(parser.json);** /////////////// var todos = []; var nextTodoItem = 1; app.use(bodyParser.json); ap ...

The correct method for accessing descendants in THREE.js in the latest version, r68

As of the release r68, the getDescendants() method has been removed from the THREE.Object3D API. How should we now achieve the same functionality without any warning message being provided? ...

Tips for redirecting to a 404 page when encountering invalid data in getStaticProps

For my Next.js application, I need to retrieve all articles written by a specific author. The author's ID is obtained from the request parameters. I have already pre-generated some authors using getStaticPaths. Within the getStaticPaths function, I h ...