Is there an alternative approach? Javascript

I am exploring different methods to rework this specific code snippet:

function createCounter() {
    let number = 0;

    function increment() {
        return number++;
    }

    // Problematic section
    increment.setValue = (newValue) => number = newValue;
    increment.decrement = () => number--;
    // End of problematic section

    return increment;
}

let myCounter = createCounter();

console.log(myCounter()); // 0
console.log(myCounter()); // 1

myCounter.setValue(10); // set the count to a new value

console.log(myCounter()); // 10

myCounter.decrement(); // decrease the number by 1

console.log(myCounter()); // 10 (instead of 11)

How can I achieve this differently?

Here's an alternative way you can refactor your code to achieve the same functionality, using closures, which might simplify management and enhance readability:

function createCounter() {
    let number = 0;

    return {
        increment: function() {
            return number++;
        },
        setValue: function(newValue) {
            number = newValue;
        },
        decrement: function() {
            return --number;
        }
    };
}

let myCounter = createCounter();

console.log(myCounter.increment()); // 0
console.log(myCounter.increment()); // 1

myCounter.setValue(10);
console.log(myCounter.increment()); // 10

myCounter.decrement();
console.log(myCounter.increment()); // 10

This approach uses an object to keep related methods together, making it clear what functionalities are available for your counter. Such structural changes not only simplify code but also promote code maintainability and scalability.

Try using closures to encapsulate the counter methods. Here's a simplified version:

function createCounter() {
    let number = 0;

    return {
        increment: () => number++,
        setValue: (newValue) => number = newValue,
        decrement: () => number--
    };
}

let myCounter = createCounter();

console.log(myCounter.increment()); // 0
console.log(myCounter.increment()); // 1

myCounter.setValue(10);

console.log(myCounter.increment()); // 10

myCounter.decrement();

console.log(myCounter.increment()); // 10

Another approach to this problem involves using JavaScript classes which can provide a clearer structure and facilitate the addition of new functionalities as needed:

class Counter {
    constructor() {
        this.number = 0;
    }

    increment() {
        return this.number++;
    }

    setValue(newValue) {
        this.number = newValue;
    }

    decrement() {
        return --this.number;
    }
}

const myCounter = new Counter();

console.log(myCounter.increment()); // 0
console.log(myCounter.increment()); // 1

myCounter.setValue(10);
console.log(myCounter.increment()); // 10

myCounter.decrement();
console.log(myCounter.increment()); // 10

By using a class, the counter state and methods are well encapsulated. This design pattern is usually easier to scale and makes your code more reusable. JavaScript classes not only encapsulate data but also provide a clean and clear structure that is familiar to developers with experience in other object-oriented programming languages.