Factory Function doesn’t update output?

Hi, I’m new to JS and coding in general. Trying to get a better grasp of objects and factory functions. Can someone help explain why the factory function below doesn’t update the output when a property is changed?

//this is a factory function. it is a function that returns a new object
function circleArea(radius = 10) {
    return {
        radius: radius,
        get area(){
            return radius ** 2 * Math.PI;
        },
    };
};

// this is an object made from Factory function 
const a = circleArea(12);
console.log(a); 

a.radius = 10;
console.log(a.area);
//this function doesn't update the area when radius is changed

In the function radius is always 12 in the getter because that is what it was created with.
It’s not referring to the radius in the object returned. To reference the object use this.radius in the getter and it works.

3 Likes

Hii~
You gotta use this to reference the object
H

Thank you so much!

This is helping me understand better. I needed it to reference the new parameter of the object by calling “this”. Here is the amended code that works for anyone’s reference.

//this is a factory function. it is a function that returns a new object
function circleArea(radius = 10) {
    return {
        radius: radius,
        get area(){
            return this.radius ** 2 * Math.PI;
        },
    };
};

// this is an object made from Factory function 
const a = circleArea(12);
console.log(`radius of ${a.radius} = ${a.area}`); 

//this changes the radius and returns a new area 
a.radius = 10;
console.log(`radius of ${a.radius} = ${a.area}`); 

The issue here is that the whole point of a factory function is to protect that variable, and to provide accessors to and from it. Objects in javascript traditionally don’t support private properties, so factories are a great workaround.

The same factory that doesn’t expose the radius directly can be defined like this:

function circleArea(radius=10){
  // here, we have a variable radius.
  return {
    get radius(){
      // This is accessing the variable inside the closure
      return radius;
    }
    set radius(value){
      // by defining a setter method on our object, we can "gatekeep" for
      //  our private variables, like radius. In this case, we error for a
      //  negative value.     
      if(value<0) throw new Error("Negative radius not supported, bud.");
      radius=value;
    }
    get area(){
      // again, we simply access the variable, *not* the object property!
      return radius ** 2 * Math.PI;
    }
}

const a = circleArea(12);

console.log(`Radius of a: ${a.radius}, area: ${a.area}`);
// we are using the getter on the right, and the setter on the left!
a.radius = a.radius*1.5; 

console.log(`Radius of a: ${a.radius}, area: ${a.area}`);

So we define getters and setters for radius. And from the outside, it looks like a property on our object - but in our object definition, we can see that we are using these as privileged methods to get a private variable within our factory.

1 Like

First, thanks a lot for the thoughtful reply Tobias.

This makes a lot of sense and fits in with what I’m learning about abstraction.

If implemented in ECMA6, I understand the same outcome can be achieved with class and weak maps . Am I on the right concept?

… Typed on mobile. Forgrive any spelling hiccups :wink:

1 Like

No worries, and yes you’re exactly right. Symbols and weakMaps can provide much the same result.

The advantage to pure factories over objects, for me, is the explicit structure of a scope tree over the slippery nature of context. The this reference can change, not only based on where you call it from, but what you call it on [lexical context vs execution context].

A great discussion on balancing functional and object oriented coding has been assembled by Eric Elliott. A series of Medium blog posts have become the book Composing Software, well worth the read.

This topic was automatically closed 182 days after the last reply. New replies are no longer allowed.