Invoke a method on each property in JS

Is there any way to invoke a method on each property instead of calling it on the obj and giving property as argument?
For example if I have an object like this:

const obj = { person: "John Smith" };

I know I can add a method like the following to the object:

addM(p) { return "Mr. " + p; }

and then call it as:

obj.addM(obj.person)

But is there any way to define the method that can be invoked like:

obj.person.addM()

or even better: obj.person.addM

Sorry if I simplified the question too much, I believe I can figure out how to code what I want in my project if I know the solution of this simple problem.
Actually I have some nested objects so please consider it in answering if necessary.
For example if I have:

const obj = {
  person1: { firstName: "John", lastName: "Smith" },
  person2: ...,
  .
  fullName() {
    return this.firstName + this.lastName;
  }
};

I want to invoke it as obj.person1.fullName

  • This does NOT answer your question and is purely an opinion: A common Javascript pattern is to not mix objects and data. Let data be data, and create functions (not methods) to act on that data, especially if you’re simply returning values rather than mutating the object itself. Otherwise, you could make "John Smith" a class with a valueOf method, or modify the default String prototype to add methods to it, and deal with serializing/deserializing that data and/or the class constructor to create it.

    – 

  • If obj.person is a string, you cannot (and definitely should not) add a .addM() method to it. If obj.person is an object consisting of firstName and lastName properties, it does make sense to add an addM() method it. If you have many objects, consider defining the method only once and adding it to each of the objects, or start using classes.

    – 

  • I want to invoke it as obj.person1.fullName” – really? Didn’t you mean obj.person1.fullName()?

    – 

  • Please edit your question to clarify the above two points – remove the {person: "John Smith"} example if it doesn’t actually represent your real code

    – 

  • @Bergi I have both situations in my project, strings and objects of strings as value . I know it is not good a idea to add a method to the String prototype but I supposed there could be a way to do it in an object. And about the () this could be achieved with a simple getter.

    – 

Bind prototypes of ES6 classes to any of your data, to handle your data in an OOP way:

class Person{
  get fullName() {
    return this.firstName + ' ' +  this.lastName;
  }
}

const obj = {
  person1: { firstName: "John", lastName: "Smith" },
  person2: { firstName: "Jane", lastName: "Doe" },
};


for(const prop in obj){
  if(/^person\d+$/.test(prop)){
    Object.setPrototypeOf(obj[prop], Person.prototype);
  }
}


console.log(obj.person1.fullName);
console.log(obj.person2.fullName);

You can use Object.defineProperty, As the MDN explain: “The Object.defineProperty() static method defines a new property directly on an object, or modifies an existing property on an object, and returns the object.”

In this example, use Object.defineProperty for every obj child add a new property fullName

const obj = {
  person1: { firstName: "John", lastName: "Smith" },
  person2: { firstName: "Jane", lastName: "Doe" }
};

Object.keys(obj).forEach(key => {
  Object.defineProperty(obj[key], 'fullName', {
    get() {
      return `${this.firstName} ${this.lastName}`;
    }
  });
});

console.log(obj.person1.fullName); // John Smith
console.log(obj.person2.fullName); // Jane Doe

put full name function in your object

const obj = {
      Name: "John",
      fullName() {
        return `MR ${this.Name}`;
      }
};

to call new Name

obj.fullName();

Leave a Comment