2

I am a newbie to nodejs. I am writing a helper function to build JSON using a schema, I am trying to add functions (mostly setters) to set values. The following is a simple version of it.

function Task() {
  this.action = {};
  this.schedule = {};
}

function capitalize(str) {
  return `${str[0].toUpperCase()}${str.slice(1)}`;
}

const scheduleProps = [
'startAt',
'repeatEvery',
'endAt',
'count',
'interval'
];

Add methods to it dynamically

for(var i=0; i<scheduleProps.length; i++) {
  Object.defineProperty(Task.prototype, `set${capitalize(scheduleProps[i])}`, {
    enumerable: true,
    configurable: false,
    writable: true,
    value: (value) => {
      this.schedule[scheduleProps[i]] = value;
    }
  });
}

When I call the following way I expect obj.schedule.repeatEvery to contain value 10.

obj = new Task();
obj.setRepeatEvery(10);

Instead I get

TypeError: Cannot set property 'repeatEvery' of undefined

I even tried to set the functions like so

  Task.prototype[`set${capitalize(scheduleProps[i])}`] = (val) => {
    this.schedule[scheduleProps[i]] = val;
  }

In this case I get

TypeError: Cannot set property 'interval' of undefined
at Task.(anonymous function) [as setRepeatEvery]

How can I set methods to a function.prototype dynamically? Thanks a lot for your help

6
  • 4
    Where is the loop run? Lambda (arrow) functions won't have the correct this scope if that loop doesn't run inside a member method. try using a regular function Commented Mar 24, 2017 at 22:42
  • Awesome Balázs!! I had to move it into the constructor and it worked. I need to have them as lambda function in order to set the functions to the main function prototype Commented Mar 24, 2017 at 22:54
  • JSON is a data exchange format, like XML or YAML. I don't see any JSON in your example. JavaScript objects are not JSON. Commented Mar 24, 2017 at 22:58
  • Another question I had was which of the methods is better? Is defining by Object.defineProperty() prefered over Task.prototype[methodName] ? Commented Mar 24, 2017 at 22:59
  • What are you trying to accomplish? Can you show what you want the prototype to look like after you add these dynamic things to it? And, then how you want to access things. For starters, your for loop has already run to completion so your i variable is wrong when your value method gets called. Commented Mar 24, 2017 at 23:04

1 Answer 1

1

You were facing that issue mainly because of function assignment for "value" key.

You can find some changes there which is creating a closure and also changed the syntax of assigning a function at key of an object.

Closure is created to maintain the value of i for that particular iteration.

function Task() {
  this.action = {};
  this.schedule = {};
}

function capitalize(str) {
  return `${str[0].toUpperCase()}${str.slice(1)}`;
}

const scheduleProps = [
    'startAt',
    'repeatEvery',
    'endAt',
    'count',
    'interval'
];

for(var i=0; i<scheduleProps.length; i++) {
  Object.defineProperty(Task.prototype, `set${capitalize(scheduleProps[i])}`, {
    enumerable: true,
    configurable: false,
    writable: true,
    value: (function(i) { return function(value) { this.schedule[scheduleProps[i]] = value;} })(i)
  });
}

obj = new Task();
obj.setRepeatEvery(10);

Sign up to request clarification or add additional context in comments.

5 Comments

Thanks Jitendra, I had to move the for loop into the Task() constructor. By adding anonymous function the this is the scope of the anonymous funciton. I wanted the methods to be added to the Task.prototype
By above code those functions are already on prototype of Task Class. You can run this code in Browser console and after that type "Task.prototype." this will shows you all there.
An answer should explain why the OP has their issue and how to fix it.
@RobG Thanks. Added Explanation for the same.
Thanks a lot Jitendra. As you had mentioned I was missing the array scope when the function was actually executing. Awesome.. !

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.