Is this a valid use case for javascript closure?
Asked Answered
N

4

9

I have looked through all the other (excellent) answers on SO (especially this: How do JavaScript closures work?) but I wanted your feedback on my understanding of the concept.

I understand that one use case is to hide the implementation of private methods from public access.

The other one that I think of is having it as a factory generator:

<script>

function carFactory( make ) {
    return {
        manufacture: function ( model ) {
            console.log("A " + make + " " + model + " has been created");
        }
    }
}

toyotaFactory = carFactory("toyota");
hondaFactory = carFactory("honda");

toyotaFactory.manufacture("corolla");
toyotaFactory.manufacture("corolla");
hondaFactory.manufacture("civic");

</script>

This outputs:

A toyota corolla has been create
A toyota corolla has been created
A honda civic has been created 

So do you think its a valid use case for closures (i.e. creating multiple factories using the same code base)? Or can I achieve the same thing using something much better?

Please note that the question is less about the technical implementation of closures and more about valid use cases in application design / development.

Thanks.

Nita answered 16/7, 2012 at 0:21 Comment(3)
Looks good! I see nothing wrong with it.Mackintosh
Technically, you don't need m -- you can just use make directly.Giron
thanks a lot everyone (almo, linuxios, josh, jfriend, et al.), your comments added to my confidence and knowledge regarding understanding of closures.Nita
B
4

Yes, keeping variables private is a valid use for a closure. It allows you to have private access to a variable without making it a public member.

See this reference for other examples: http://www.crockford.com/javascript/private.html

Bombshell answered 16/7, 2012 at 0:30 Comment(0)
M
1

If I'm understanding your question correctly, you aren't concerned with keeping the make property private? If that's the case, then a closure isn't really necessary, and you could achieve the same functionality using a prototype...

function carFactory(model){
  this.m = make;
}

carFactory.prototype.manufacture = function(model){
  console.log('A ' + this.m + ' ' + model + ' has been created');
}

Which has associated performance benefits (reduced memory and increased speed), as per this question.

Mannerly answered 16/7, 2012 at 0:39 Comment(5)
This stores the model name, but does not keep it private. Member variables are available to anyone. The advantage of the OP's closure is that the model name is truly private.Bombshell
yeah, edited my answer to be a bit more specific. this is only a workable answer if keeping make private is unnecessary. if it is, though, then a closure is the best solution.Mannerly
I thought the whole point of the closure in the OP's question was privacy. I'd agree that if privacy isn't needed, then the closure is more complicated (and probably worse memory consumption) than needed. If public, a member variable is the most straightforward.Bombshell
yes, it was (even though my example makes it seem less important), but the concept i was trying to grasp was when i wanted to keep data private (like no one can change the factory once created).. but market's post was good knowledge for me (and hopefully others) in general.Nita
Note that in ECMAScript nothing is truely private. The manufacture method can be replaced to return a different make, so you're back where you started in terms of privacy (and the implied security).Amass
J
0

Closures are extremely powerful construct, with a lot of useful uses. The one you used there is actually kind of a "hack". The most common use for closures, is when you have implemented some functionality that "does something" in the middle... And that "does something" can be configured to more or less whatever you want... For example the jQuery ajax functionality can "do something" when the request has an error, or when it succed, etc... If you didn't have closures, you'd only be able to pass a "statically defined" function, which will probably need to gather the context needed to do whatever you want it to do from global variables, or you'll have to use the same signature for all functions like what it's done in C or C++ like function (customData) {} ... Closures allows you to "dynamically build functions" at runtime, reteining the context that they have when they were created, so you can pass to the modules that need to "do something" nearly anything you want, in a really easy way (in contract with what you'd do in c or c++ or without closures, that it's ugly, error prone, and a hack too).

So whenever you must "configure" some custom functionality inside something, you'll use a closure...

Jerky answered 16/7, 2012 at 0:38 Comment(0)
R
0

I was trying to come up with a practical example of information-hiding/encapsulation and this is what my attempt so far

'use strict';

const bank = (accountHolderName, initialDeposit) => {
    let balance = initialDeposit;
    const add = (amount) => {
        balance += amount;
    }

    let subtract = (amount) => {
        balance -= amount
    }

    let printBalance = () => {
        console.log(accountHolderName, "has balance of", balance, "dollars");
    }

    return {
        credit: add,
        debit: subtract,
        balance: printBalance
    }
}

let amy = bank("Amy", 1000);
amy.balance();
amy.credit(100);
amy.balance();
amy.debit(10);
amy.balance();

let sam = bank("Sam", 50);
sam.balance();
sam.credit(50);
sam.balance();
sam.debit(100);
sam.balance();

Once you run, you would get the following output

Amy has balance of 1000 dollars
Amy has balance of 1100 dollars
Amy has balance of 1090 dollars
Sam has balance of 50 dollars
Sam has balance of 100 dollars
Sam has balance of 0 dollars

The benefits?

  • the balance variable is not directly accessible.
  • Using closures, every caller get's their own data. Amy's balance is not interfering with Sam's data
  • The callers (Amy, Sam, and others) has a nice API to work with instead of worrying about the internal details on how bank operates.

Am I missing something else?

Risible answered 3/9, 2019 at 23:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.