2

How can i get an array of the arguments of a constructor class in JS? It's possible? Thanks in advance.

class Product {
    constructor(id, name, price, category, stock){
      this.id = id;
      this.name = name;
      this.price = price;
      this.category = category;
      this.stock = stock;
    }  
};

console.log(Product.constructor.params);

//expected output = ['id', 'name', 'price', 'category', 'stock'];
sonEtLumiere
  • 4,461
  • 3
  • 8
  • 35
  • Without using type notation or a typed language like typescript? – evolutionxbox Jul 10 '21 at 22:04
  • i'm using typescript actually – sonEtLumiere Jul 10 '21 at 22:07
  • Does this help? https://stackoverflow.com/questions/3404057/determine-original-name-of-variable-after-its-passed-to-a-function – evolutionxbox Jul 10 '21 at 22:07
  • 1
    What are you trying to do? You already know the arity/arguments of your constructor, and the class properties. – Andy Jul 10 '21 at 22:09
  • I need to get the constructor arguments to compare and filter with another logic in my code – sonEtLumiere Jul 10 '21 at 22:17
  • My point is that you already _know_ what the class properties are. You specified them. Are they going to change? – Andy Jul 10 '21 at 22:26
  • No, will not change. But if i add some new property in the constructor i have to update several pieces of code validation. The instances of Products sometimes are converted to strings so for that reason i would like to validate with no need to make an instance of a new product again. – sonEtLumiere Jul 10 '21 at 22:35

3 Answers3

3

Inspired form @Porter answer and @evolutionxbox, I think that a reliable way would be using .match() like this:

class Product {
  constructor(id, name, price, category, stock, unusedArgument) {
    this.id = id;
    this.name = name;
    this.price = price;
    this.category = category;
    this.stock = stock;
  }
}

class Noarguments {
  constructor() {
  }
}

// A function
function getClassContructorParams(obj){
  let match = obj.toString().match(/constructor\((.+)\)/)
  
  if(match && match[1]){
    return match[1].split(",");
  }
  
  // If no match
  return []  
}


console.log(getClassContructorParams(Product))

/// Testing a class with no constructor arguments will return an empty array
console.log(getClassContructorParams(Noarguments))

My previous answer was returning the object properties, which may be different from the arguments used in the constructor...

Now using .match() will ensure what is returned really are the constructor arguments.

Louys Patrice Bessette
  • 33,375
  • 6
  • 36
  • 64
2
let s = Product.toString();
let params = s.substring(s.indexOf('(')+1, s.indexOf(')')).split(',')
Porter
  • 193
  • 1
  • 8
1

My point in the comments was it seems you're coming at this problem from the wrong direction. Maybe take this approach. Have an array of labels, and array of data, and pass those into the class. You'll still have the array of labels to access (and validate) in your other code, and everything will still work.

const labels = [ 'id', 'name', 'price', 'category', 'stock' ];

const data = [ 1, 'Bob', 100, 2, 1];

class Product {

    constructor(labels, data) {
      data.forEach((el, i) => this[labels[i]] = el);
    }
    
};

console.log(new Product(labels, data));
console.log(labels);

Or, if your products are identical in terms of properties you could just use an array of them, and use Object.keys to get the labels of the first object.

const data = [{ id: 1, name: 'Bob', price: 100, category: 2, stock: 1 }];
const labels = Object.keys(data[0]);

class Product {

    constructor(data) {
      for (let key in data) {
        this[key] = data[key];
      }
    }
    
};

console.log(new Product(data[0]));
console.log(labels);
Andy
  • 61,948
  • 13
  • 68
  • 95