1

I have a class instance whose constructor takes an object or a JSON string representing that object. *

Because that JSON comes from a remote source, I like to ensure that the properties all have a lowercase first letter. However I've noticed that the method I'm using to do so (Object.keys()) ignores prototype methods. This makes sense after reading the documentation. I considered Object.getOwnPropertyNames() instead but given that I'm not dealing with enumerable vs non-enumerable (as far as I know), that wouldn't make a difference.

Is there an alternative method I can use to lowercase the first letter of all keys and prototype methods?

Thanks. Demonstration below.

class B {
  constructor() {
    this.MyProperty = "Hello world!";
  }
  MyMethod() {}
}

class A {
  constructor(b) {
    console.log(`MyMethod exists before lowercasing: ${!!b.MyMethod}`);
    b = Object.keys(b).reduce((copy,key) => ({...copy,  [`${key[0].toLowerCase()}${key.slice(1)}`]: b[key]}),{});

    console.log(`MyMethod exists after lowercasing: ${!!b.myMethod || !!b.MyMethod}`);
    console.log(`MyProperty has been lowercased: ${!!b.myProperty}`);
  }
}

let b = new B();
let a = new A(b);

* I've removed this for sake of brevity.

Santi
  • 416
  • 4
  • 21
  • 1
    `MyMethod` actually is non-enumerable as well, so yes you should deal with that. – Bergi Jul 27 '19 at 19:45
  • Thanks for that heads-up. Perhaps I should kill two birds with one stone here and just make the methods properties instead. – Santi Jul 27 '19 at 19:54
  • 1
    TBH I think your `A` shouldn't deal with this at all. Just have it expect `B` instances, and name `B`s methods reasonably. Do any necessary conversion of property names only when parsing the JSON, not on an already existing object (or worse, instance with prototype). – Bergi Jul 27 '19 at 19:56
  • @Bergi Appreciate the input. I'll likely go that route then. I'll leave this open in case someone submits an answer to the (misguided) question I'd asked, otherwise I'll delete it. – Santi Jul 27 '19 at 20:09
  • For your original question, go by the approach I outlined in [List Down All Prototype Properties of an Javascript Object](https://stackoverflow.com/q/30158515/1048572) (although I guess you'll want to stop at `Object.prototype`, not `null`) – Bergi Jul 27 '19 at 20:28

1 Answers1

1

You could get the prototype from the instance using Object.getPrototypeOf(instance) and then invoke Object.getOwnPropertyNames() on the prototype to get the list of prototype methods.

Using Array.prototype.reduce() you can combine the prototype methods as well as the keys of the object instance you have given into a single object and apply your lower-casing logic subsequently:

class B {
  MyMethod() { return true }
}

class A {
  constructor(b) {
    console.log(`MyMethod exists before lowercasing: ${!!b.MyMethod}`);
    var proto = Object.getPrototypeOf(b);
    var comp = Object.getOwnPropertyNames(proto).reduce((obj, key) => {obj[key] = proto[key]; return obj}, {...b})
    b = Object.keys(comp).reduce((copy,key) => ({...copy,  [`${key[0].toLowerCase()}${key.slice(1)}`]: b[key]}),[]);
     
    console.log(`MyMethod exists after lowercasing: ${!!b.myMethod || !!b.MyMethod}`);
  }
}

let b = new B();
let a = new A(b);
Fullstack Guy
  • 16,368
  • 3
  • 29
  • 44
  • 1
    Perhaps I'm misunderstanding but doesn't this take me from having only the keys but *not* the prototype, to having *only* the prototype but not the keys? – Santi Jul 27 '19 at 19:52
  • @Santi class **methods** are declared as a **non-enumerable property of the prototype**, so in your case you need to access them from the prototype. – Fullstack Guy Jul 27 '19 at 19:54
  • I understand that and I appreciate the answer, however I'm trying to extend my method that currently lower-cases the key names to *also* lower-case prototype methods. My point above is that, if `class B` had a constructor and properties, it seems like they would no longer be copied/lowercased within `class A`. I've modified my example to reflect this. – Santi Jul 27 '19 at 19:57
  • @Santi My bad, I understand your problem now can you please check my updated answer? – Fullstack Guy Jul 27 '19 at 20:18