3

I looked through the suggested links but can't seem to find the term for a function that acts like a class (is it a constructor function? doesn't have that keyword either!) but doesn't use the new keyword, nor class.

I've used both this example's pattern and the class pattern in my code but realized I don't know how to describe the former.

I think this is in part because I learned JS recently, have seen class thrown around a lot, yet looking through my notes of not-ES5,6,7,2018,2020 etc. can't seem to find what var aCounter = counterFunction() is called for the life of me.

I know what the result of what i'm doing is, how to work it, etc. but why no constructor(), no new, no class, no etc.prototype.etc pattern? I know i'm creating an object, calling a method existing Within the object, etc. I believe i'm beginning to ramble.

Lo, an example

const counterFunction = () => {
    let val = 0

    return { 
      increment() { val++ }, 
      getVal() { return val }
    }
}

which is || can be instantiated (?) like so:

let aCounter = counterFunction() // where i'm getting tripped up

and works like

aCounter.increment() // 1
aCounter.increment() // 2
aCounter.getVal() // 2 

I know this is rambling, but help! I think it will make things click more inside once this lexical puzzle piece is put into position!

saylestyler
  • 389
  • 1
  • 4
  • 20

4 Answers4

3

That is just a function that returns an object literal, which does not act like a class (doesn't have a prototype, and as you pointed out, does not use new, etc).

The functions that are set as the properties of this object (which you store in aCounter) seem to act like class methods because they keep the reference to the variable val alive, but this is not because val is in any way associated with the actual object.

Instead, those functions are closures that keep the reference to the variable alive for as long as the functions themselves are alive.

So to answer your question, what you have described doesn't have any name in particular. It's just a function that returns an object.

Edit:

You asked why there is no constructor() or related syntax in this pattern. Object literals in JavaScript are just mappings of names and values:

const x = { a: 3, b: "hello" };

You do not need a constructor for this, and there is no prototype because it was not instantiated using a constructor. On the other hand, classes and constructor functions are templates for objects that will be created later, and those objects do have a prototype and a constructor because the template contains logic that initializes the object.

class A
{
    constructor() 
    {
        this.a = new Date();
        this.b = this.a.toString(); // you cannot do this in an object literal
    }
}

const x = new A();
laptou
  • 6,389
  • 2
  • 28
  • 59
1

What you showed there is nothing special. It is just a normal function that has a closure.

Though, you can call it as a type of design pattern.

It looks similar to Revealing Module Pattern where you can separate public property and private property.

Below is an example (not a good one tho):

var counter = function(){

  var privateCount = 0;
  var privateHistory = [];
  
  return {
    getVal: function(){
      return privateCount;
    },
    increment: function(){
      privateCount++;
      privateHistory.push('+');
      return this.getVal();
    },
    decrement: function(){
      privateCount--;
      privateHistory.push('-');
      return this.getVal();
    },
    publicHistory: function(){
      return privateHistory;
    }
  }
}

var aCounter = counter();
console.log(aCounter.increment());
console.log(aCounter.decrement());
console.log(aCounter.publicHistory());

Here, you can't directly manipulate the private variables that I don't expose to you.

You can only manipulate those private variables only if I expose the function to you. In this case, the .increment() and .decrement() function.

As you can see, there is no class, no prototype, no constructor.

yqlim
  • 6,898
  • 3
  • 19
  • 43
1

I can see how you may get tripped up, let's go through your code and explore what's going on:

const counterFunction = () => {
    let val = 0

    return { 
      increment() { val++ }, 
      getVal() { return val }
    }
}

At this point counterFunction is a variable that points to a function, it's essentially a function name. The ()=>{...} is the function body or function definition and within it the return statement shows that it returns an unnamed object with two property methods.


let aCounter = counterFunction() // where i'm getting tripped up

This is calling your previously defined function, which again returns the object with two methods and assigns it to the variable aCounter. If you did the same thing again for a variable called bCounter they would hold two independent objects.


and works like

aCounter.increment() // 1
aCounter.increment() // 2
aCounter.getVal() // 2 

Because the method inside the object refers to a variable outside the scope of the object, but within the function body, a closure is created so that the state of val may be retained. Because the variable is in use, the browser's cleanup process skips over it, so the function is still kept in memory, I believe until the object is destroyed and the function's variable is no longer used.

vol7ron
  • 40,809
  • 21
  • 119
  • 172
1

Question:

What is it called when a function behaves like a class but doesn't use the class keyword, nor “new” keyword (in Javascript)?

Answer:

It's called a "factory function".

Factory functions usually return a object of a consistent type but are not instances of the factory function itself. Returned objects would rarely inherit from the factory function's prototype property, and calling the factory function does not require new before the function being called.

traktor
  • 17,588
  • 4
  • 32
  • 53