Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

As much as I understand both concepts, I can't see how can I take advantage of JavaScript's closures and prototypes aside from using them for creating instantiable and/or encapsulated class-like blocks (which seems more of a workaround than an asset to me)

Other JS features such as functions-as-values or logical evaluation of non-booleans are much easier to fall in love with...

What common programming problems are best solved by using propotypal inheritance and closures?

share|improve this question
1  
OO is solved by prototypical inheritance. In JavaScript prototypes are your OO mechanism. And closures are what you use to bind state to a function. I'd recommend you try node.js or anything else that uses asynchronous logic a lot, you'll easily fall in love with closures. –  Raynos Nov 21 '11 at 13:23
    
Perhaps I didn't make myself clear enough - I'm already aware of achieving OO via prototypes, but there have to be more uses of that feature aren't there? Feel free to put some examples on asynchronous logic. –  vemv Nov 21 '11 at 13:32
1  
you make it sound like achieving OO via prototypes is a minor feat, "surely prototypes must have more uses then OO" –  Raynos Nov 21 '11 at 13:37
2  
@vemv: Prototypes are there to give you OO. Period. Anything else is really just abuse. –  Jan Hudec Nov 21 '11 at 13:59
2  
@vemv they are not exotic, the javascript community just does a very poor job at teaching prototypes Go read about protoypes –  Raynos Nov 21 '11 at 14:40

3 Answers 3

  1. Closures are what makes functions as values useful. When you are passing the function, you almost certainly need it to take some context along. Which is exactly what closures do.

  2. Prototypes are just a simpler version of class inheritance. Instead of having instances and classes (represented by special kind of instances in dynamic languages anyway), you have just instances and the prototype is the class (and it's prototype is the base class). So they basically solve the same problems, just the prototypes are easier to implement (that's why JavaScript chose them), somewhat harder to use (well, just lack of syntactic sugar) and for better or worse easier to abuse.

share|improve this answer
    
"when passing functions you almost certainly need context" not really, look at C and their function pointers, they don't need context. Generally if you pass functions around you give these functions the context they need. Sure closures are a great way of passing context, but far from the only –  Raynos Nov 21 '11 at 14:15
    
"prototypes are easier to implement (that's why JavaScript chose them)" That's a vague (and highly likely to be false statement) without any kind of reference. –  Raynos Nov 21 '11 at 14:39
    
@Raynos: in C we often pass context to functions via a void* data argument to be downcast by the called function. –  kevin cline Nov 21 '11 at 16:23
1  
@Raynos: I am looking at C function pointers and they are utter pain to use unless the code taking them passes through an extra void * with context. As for prototypes, they are obviously easier to implement, since you have just one kind of non-primitive objects and one uniform way of accessing members (and not separate for instance and class members and no special behaviour of meta-objects). While I don't have a reference that ECMAScript designers really chose prototypes for this reason, minimal interpreter was important design goal, so it's very likely. –  Jan Hudec Nov 21 '11 at 18:39
    
@JanHudec I think it's a couple of orders of magnitude more likely that JavaScript has prototypes because the prototypical OO language Self influenced brendan when he wrote javascript. –  Raynos Nov 21 '11 at 19:29

Closures don't solve any programming problems that can't be solved without them. However, this can be said for any language feature not needed for Turing completeness, so it doesn't mean much.

Think about how you have to rewrite any code that uses a closure, to not use a closure. You would probably give the function with the closure extra properties so it could hold it's state between calls. Which would just be copying the variables that are already in scope into properties of the same name on the function, so it would be the kind of mindless typing exercise that makes you want to yell at the screen "why can't the stupid compiler (interpreter, whatever) figure this out?" That's what closures are, the stupid compiler is smart enough to figure it out.

share|improve this answer
    
Yesterday I first realised how to use closures in a meaningful way - they can make separation of concerns much lighter: one component would send an anonymous function to another, which body makes a reference to a field the second component is not aware of. Thank you based compiler! –  vemv Nov 24 '11 at 10:11
    
@vemv - Which you could do without closures by making an object that holds the reference to the field the second component is not aware of and passing it to the second component, but it's such a huge pain compared to a closure that you might well decide not to do it. –  psr Nov 25 '11 at 17:16

Closures are great for asynchronous logic.

It's mainly about organization of code for me. Having a bunch of local functions to split up what the code is doing is nice.

create: function _create(post, cb) {
    // cache the object reference
    var that = this;

    function handleAll(err, data) {
        var rows = data.rows;

        var id = rows.reduce(function(memo, item) {
            var id = +item.id.split(":")[1];
            return id > memo ? id : memo;
        }, 0);
        id++;


        var obj = {
            title: post.title,
            content: post.content,
            id: id,
            // refer to the object through the closure
            _id: that.prefix + id,
            datetime: Date.now(),
            type: "post"
        }

        PostModel.insert(obj, handleInsert);
    }

    // this function doesn't use the closure at all.
    function handleInsert(err, post) {
        PostModel.get(post.id, handleGet);
    }

    // this function references cb and that from the closure
    function handleGet(err, post) {
        cb(null, that.make(post));
    }

    PostModel.all(handleAll);
}

Here's another example of a closure

var cachedRead = (function() {
    // bind cache variable to the readFile function
    var cache = {};

    function readFile(name, cb) {
        // reference cache
        var file = cache[name];
        if (file) {
            return cb(null, file);
        }

        fs.readFile(name, function(err, file) {
            if (file) cache[name] = file;
            cb.apply(this, arguments);
        });
    }

    return readFile;
})();

And another example

create: function _create(uri, cb, sync) {
    // close over count
    var count = 3;

    // next only fires cb if called three times
    function next() {
        count--;
        // close over cb
        count === 0 && cb(null);
    }

    // close over cb and next
    function errorHandler(err, func) {
        err ? cb(err) : next();
    }

    // close over cb and next
    function swallowFileDoesNotExist(err, func) {
        if (err && err.message.indexOf("No such file") === -1) {
            return cb(err);
        }
        next();
    }

    this.createJavaScript(uri, swallowFileDoesNotExist, sync)

    this.createDocumentFragment(uri, errorHandler, sync);

    this.createCSS(uri, swallowFileDoesNotExist, sync);
},

The alternative to using closures is currying variable into functions using f.bind(null, curriedVariable).

Generally though, asynchronous programming logic uses callbacks and manipulating state in callbacks either relies on currying or closures. personally I prefer closures.

As for uses of prototypical inheritance, it allows OO? Does prototypical inheritance really need to do more then that for it to be considered "useful". It's an inheritance tool, it allows inheritance, that's useful enough.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.