Is it possible to use programming to invoke a function with the identical name from within another function in Javascript or Typescript?

Currently, I am working with Typescript but presenting this question in Javascript. Any assistance for either language would be greatly appreciated.

I have two objects that share the same interface. My goal is to create a third object with the same interface, where each function calls corresponding methods from both of the objects it contains. Is there a method to generate all these functions programmatically to avoid manually typing them out?

c = console.log;  // shorthand
obj1 = function() {}
obj1.prototype = {
  foo: (x) => { c("1" + x) },
  bar: (x, y) => { c("1" + x + y) }
}
obj2 = function() {}
obj2.prototype = {
  foo: (x) => { c("2" + x) },
  bar: (x, y) => { c("2" + x + y) }
}

obj3 = function() {
  this.o1 = new obj1()
  this.o2 = new obj2()
}
obj3.prototype = {
  foo: function(x) {
    this.o1.foo(x);
    this.o2.foo(x);
  },
  bar: function(x, y) {
    this.o1.bar(x, y);
    this.o2.bar(x, y);
  }
}

I'm seeking a way to define obj3 without the need to individually write each member function due to having quite a few of them.

Answer №1

If you want to create a custom proxy, consider using the Proxy object:

function createCustomProxy(objects) {
    return new Proxy(objects[0], {
        get: function(target, name) {
            var self = this;
            
            return function() {
                var result;

                for (let obj of objects) {
                    result = obj[name].apply(self, arguments);
                }

                return result;
            };
        }
    });
}

In your scenario, use the custom proxy like this:

var newInstanceOfObject = createCustomProxy([new someObj1(), new someObj2()]);

Now, newInstanceOfObject will act like someObj1, but will execute the same methods from someObj2.

Please note that this implementation does not handle non-function properties of the objects, but it can be easily extended to include that functionality.

Answer №2

To access methods, you can use dictionary syntax:

let str = "Hello world";
str.toUpperString(); // returns "HELLO WORLD"
str["toUpperString"](); // same as above

A generalized approach involves implementing a lower-level method first:

Assume you have object obj containing references to x and y

function executeMethod(obj, name) {
    // Error handling logic could be included here
    obj.x[name]()
    obj.y[name]()
}

You can now execute executeMethod(obj, "action") which will trigger obj.x.action() and obj.y.action()

This isn't a complete solution, but it gives you a starting point.

Since prototypes are essentially plain dictionaries, you can easily enumerate methods in the prototype of one object and add methods to the prototype of another object.

Answer №3

If you want to duplicate objects, you can use the following methods:

// Make a shallow copy
this.o1 = jQuery.extend({}, obj1);

or

// Create a deep copy
this.o1 = jQuery.extend(true, {}, obj1);

Explaining the difference between shallow copy and deep copy

Alternatively, in pure JavaScript, you can do:

this.o1 = Object.assign({}, obj1);

It's important to fully understand Object.assign() to prevent unexpected consequences of copying objects.

An Hour Later:

After some trial and error, I discovered that the constructor function of obj3 was not creating new objects properly, so I decided to separate the cloning process. Based on my findings, this code now works correctly:

c = console.log;  // shortcut
obj1 = function() {}
obj1.prototype = {
  foo: (x) => { c("1" + x) },
  bar: (x, y) => { c("1" + x + y) }
}
obj2 = function() {}
obj2.prototype = {
  foo: (x) => { c("2" + x) },
  bar: (x, y) => { c("2" + x + y) }
}

obj3 = function() {
  this.o1;
  this.o2;
}
obj3.prototype = {
  foo: (x) => {
    obj3.o1.foo(x);
    obj3.o2.foo(x);
  },
  bar: (x, y) => {
    obj3.o1.bar(x, y);
    obj3.o2.bar(x, y);
  }
}

obj3.o1 = $.extend(true, {}, obj1.prototype); // Using jQuery or
obj3.o2 = Object.assign({}, obj2.prototype); // Using Pure JavaScript
obj3.prototype.foo(5);
obj3.prototype.bar(3,4);

Answer №4

Blender demonstrated the use of a Proxy for achieving this, but my focus was on obtaining functional typings without excessive additional work or casting.

Here is an alternative approach that performs similarly while avoiding compatibility issues with support for Proxy in IE and iOS 9.

function ClassMerger<T extends Object>(...classes: T[]): Partial<T> {
    // Helper function to execute a method on all passed instances
    let call = (method: keyof T) => (...args: any[]) => {
        for (let instance of classes) {
            if (typeof instance[method] == 'function') {
                // Typescript's type checking issue arises here.
                (instance[method] as Function).apply(instance, args);
            }
        }
    }

    let merged: Partial<T> = {};

    // Iterate through each class, adding all methods to the merged object
    for (let instance of classes) {
        for (let method in instance) {
            if (typeof instance[method] == 'function' && !merged[method]) {
                merged[method] = call(method);
            }
        }
    }

    return merged;
}

// Implementation (using your sample objects):
let merged = ClassMerger<{foo: (a: string) => void}>(new obj1(), new obj2());
if (merged.foo) {
    merged.foo('Test'); // No issues
}
// Property 'bar' does not exist on type 'Partial<{foo: (a: string) => void}>'.
merged.bar('A', 'B');

Notes:

The function returns Partial<T> because properties from your interface will not be included in the merged object. If your interface has no properties, you can cast the returned object to an instance of T.

This method requires passing instances of a class rather than creating the classes within the function. This simplifies the process and allows for classes with different constructor arguments to be easily provided.

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

Modify the characteristic of a personalized directive

I have created a unique directive that allows me to load pages within a specified div element. .directive('page', function () { return { templateUrl: function (elem, attr) { return 'pages/page-' + attr.num + &ap ...

Command for Pinging in Discord.js

I attempted to create a ping command for my bot, and here is the code I used: client.on('message', message => { if (message.content === '+ping') { message.channel.send(` ...

Extract data from JSON object

My JSON object is called idAndNames.json; [ { "id":"1", "name":"name1"}, { "id":"2", "name":"name2"}, { "id":"3", "name":"name3"} ] I'm looking to filter it by ID and name function applyFilter(id, valueItem) { return id <= valueIte ...

Tips for setting up a proxy with an enum

I am facing an issue with setting up a Proxy for an enum. Specifically, I have an enum where I want to assign a value to this.status using a Proxy. However, despite my expectations, the output "I have been set" does not appear in the console. Can anyone ex ...

What is the best way to launch a Popup window that spans from the top to the bottom of the screen?

I'm attempting to create a popup window that stretches from the top of the screen to the "applications" bar in Windows. Here's the code I'm using: function windowOpener(windowHeight, windowWidth, windowName, windowUri) { var windowHeight = ...

The CSS styling is not being rendered correctly on the AngularJS HTML page

Encountering a puzzling situation here. Our angular controller is successfully delivering data to the page, but we are facing an issue with rendering a table due to an unknown number of columns: <table border="1" ng-repeat="table in xc.tables"> ...

Find all Mondays occurring within a specified date range using Moment.js

I need to extract all Mondays within a specific date range. let start = moment(this.absence.FromDate); let end = moment(this.absence.ToDate); The user has the option to deactivate certain weekdays during this period by setting booleans. monday = true; t ...

Problem with APIGEE search function

Encountered an issue while trying to retrieve an Apigee collection using the following code snippet: var my_pc_list = new Apigee.Collection( { "client":client, "type":"pc_pedidos", qs :{ql:"limit:50"} }); Error details: {"error":"query_parse","timestamp ...

Attempting to access a variable without wrapping it in a setTimeout function will

I have a form without any input and my goal is to automatically set the "responsible clerk" field to the currently logged-in user when the component mounts. Here's what I have: <b-form-select v-model="form.responsible_clerk" :op ...

Performing operations on objects in Javascript/Jquery: The alternative to .every()

Is there a way to efficiently test for empty values in an array or object before proceeding? I want to check if all the items in a query object are blank before sending it out. While I could use a simple for loop, I'm curious if there's a more co ...

jQuery mobile menu: Scroll to content after closing the menu

I am currently working on a project where I am using mmenu for the first time. It's functioning as expected, but there is one particular issue that I would really like to have resolved. Here is the URL: What I am hoping to achieve is that when a men ...

Verify the image file format using Tampermonkey

I'm trying to determine if certain images are gifs, but the URLs used in the img tag src attribute don't include file extensions. This makes it difficult to know the image type just by looking at the source URL. I attempted to fetch the image as ...

Issue with logging messages using console.log in Knex migration script

My concern: I am facing an issue where the console.log('tableNobject: ', tableNobject) does not get logged in my knex migration script. I have attempted the following code snippets: //solution A export async function up(knex: Knex) { const ta ...

Leveraging npm packages within a Meteor project through cosmos:browserify

Trying to implement Radium, a JavaScript library for inline CSS, by following the instructions located here. In my app.browserify.js file: Radium = require("radium"); Within package.json: "radium": "0.13.4" Upon attempting to utilize Radium in the app&a ...

What is the best method for extracting `window.initialState` from a webpage?

There is a specific section in the window.initialState at the bottom of the page that I would like to extract. How can I go about retrieving this information? Note: I am utilizing Selenium with a Chromedriver for web scraping, making it impossible to use ...

Steps for determining the grade earned by an individual

Seeking assistance with my Homework assignment as I am struggling to calculate it accurately. The code provided is what I have so far, and this is the task outlined by my teacher: Develop a webpage that displays the heading "Student Grades" and allows in ...

Using Vue.js method passing an argument and setting a delay with setTimeout function

I'm struggling to understand why this particular code is functioning as it should. data: { return { userMinerals: 0, mineralsLimit: 1000, miners: 0, superMiner: 0, minerPrice: 10, superMinerPrice: 1 ...

Learn how to implement pagination in AngularJS using the $http service

I need assistance in implementing pagination using Angularjs within the Ionic Framework. Can someone provide guidance on how to code pagination for fetching data from a JSON URL? controller.js angular.module('starter.controllers', []) .control ...

Angular NG read only and searching by location

Hey there! I have an HTML file that includes Angular. I want to make an input field read-only if a certain parameter is present in the URL. I attempted using the code below but unfortunately, it didn't work: <input type="text" name="firstName" ng- ...

The Twitter widget functions properly upon initial loading, but subsequently malfunctions

I have a web application built using the Play Framework that utilizes Ajax to load view html pages into a 'container' div. $( "#container" ).load("/contactUs"); // The contactUs page contains the widget In one of my html pages, I include a Twit ...