0

I'm learning the JavaScript with Node. I like the idea of creating objects with factories, and after reading a lot on this subject, I chose to create objects with this code:

// ES6 only
'use strict';

// The base object, "object literal" syntax
let animal2 = {
  // public member
  animalType: 'animal',

  // public method 
  describe() {
    return `This is "${this.animalType}"`;
  }
};

// factory function which serves 2 purposes:
// - encapsulation, that's where private things are declared thanks to closures
// - the "real" object creation, this prevents to use "new" which is not really Js-ish
let afc = function afc() {
  // private member
  let priv = "secret from afc";

  return Object.create(animal2, {
    // Object customisation
    animalType: { value: 'animal with create'},    

    // object extension. The new objects created here get 3 new members:
    // - a private member
    // - a new property
    // - a new method to access the private member

    // new public member
    color: { value: 'green' },
    secret: {
      get: function () { return priv; },
      set: function (value) { priv = value; },
    },
    KO1() {
      console.log("KO1");
    },
    KO2: function() {
      console.log("KO2");
    }
  });
}

// creation of an animal instance
let tac = afc();

My problem is I can't figure out what's the syntax to add a function which can manipulate private data while not being just an accessor. I put here 2 examples which came to my mind (KOx), but as their names suggest, this syntax leads to: "KOx is not a function".

Honza Zidek
  • 9,204
  • 4
  • 72
  • 118
romu
  • 177
  • 1
  • 13
  • same issue with syntax for `describe() {` in `animal2`. – Davin Tryon Mar 31 '16 at 10:19
  • 1
    "*"new" which is not really Js-ish*" - who the hell told you that? – Bergi Mar 31 '16 at 10:20
  • @FrédéricHamidi `KO1()` is not a syntax error, at least not in recent node versions. – Tamas Hegedus Mar 31 '16 at 10:29
  • 2
    @FrédéricHamidi, DavinTryon: [It's not](http://stackoverflow.com/q/32404617/1048572) – Bergi Mar 31 '16 at 10:31
  • Whaou, you were very fast guys, thank out. @David : AFAIK no, the "describe" function works as expected. – romu Mar 31 '16 at 11:04
  • @Bergi, a lot of articles, those from Eric Elliot on Medium for example. – romu Mar 31 '16 at 11:07
  • @romu: OMG, that guy must be the new Crockford. Don't fear any language features only because some opionated article dissed them. Understand them, and use them where appropriate. – Bergi Mar 31 '16 at 11:29
  • Ah ah ah no @Bergi, but Crockford himself discourages the use of "new" the "JavaScript the Good Parts". – romu Mar 31 '16 at 12:21
  • @romu: That's exactly what reminded me of him :-) Regardless, `new` is one of the central parts of JS, so calling it "not Js-ish" is weird (although I can see some of the reasons why you would not want to use it). – Bergi Mar 31 '16 at 12:25

2 Answers2

2

Object.create expects an object of property descriptors as its second argument. This is why you have to use {value: …} or {set: …, get: …} everywhere.

And in fact you'd have to do the same for a method - which is just a standard property with a function as its value:

…
KO3: {value: function() {
    …
}},
…

However, I'd avoid using property descriptors when you don't need them. Object.assign is a better fit:

return Object.assign(Object.create(animal2, {
    secret: {
        get() { return priv; },
        set(value) { priv = value; },
    }
}), {
    animalType: 'animal with create',
    color: 'green',
    KO1() {
        console.log("KO1");
    },
    KO2: function() {
        console.log("KO2");
    }
});
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • Thanks @Bergi, wonderful!! You're right, the syntax with Object.create is a bit heavy, I'll try how things are with Object.assign. Many many thanks. – romu Mar 31 '16 at 11:10
0

Why don't just use the getter syntax?

return {
  __proto__: animal2, // To be honest __proto__ is not a good thing to use

  animalType: 'animal with create',

  color: 'green',
  get secret() { return priv; },
  set secret(value) { priv = value; },
  get KO3() { console.log("KO3"); },
  // or just the following, if you would like it to be a regular member function
  // KO3() { console.log("KO3"); },
};

Or without explicit __proto__:

const result = {
  animalType: 'animal with create',

  color: 'green',
  get secret() { return priv; },
  set secret(value) { priv = value; },
  get KO3() { console.log("KO3"); },
};
Object.setPrototypeOf(result, animal2);
return result;
Tamas Hegedus
  • 28,755
  • 12
  • 63
  • 97
  • Because AFAIK, it doesn't work this way with Object.create. This is the first way I tried to be honest. – romu Mar 31 '16 at 11:08
  • @romu Sure, object.create has its own input format. This is just an example how you could achieve the same result without object.create – Tamas Hegedus Mar 31 '16 at 12:28
  • ok, thanks. There are so many ways to create objects, it's pretty confusing for new comers. – romu Mar 31 '16 at 12:40