Noctis
Noctis

Reputation: 11773

why would I return a named function (object) from a javascript function?

Maybe I'm missing something obvious ... I've just started working with JavaScript, and when looking through an article about unit testing JavaScript with Jasmine, I came across this code:

function Convert(number, fromUnit) {  
    var conversions = {  
            distance : {  
                meters : 1,  
                cm     : 0.01,  
                feet   : 0.3048,  
                inches : 0.0254,  
                yards  : 0.9144  
            },  
            volume : {  
                litres : 1,  
                gallons: 3.785411784,  
                cups   : 0.236588236   
            }  
        },  
        betweenUnit = false,  
        type, unit;  

    for (type in conversions) {  
        if (conversions[type]) {  
            if ( (unit = conversions[type][fromUnit]) ) {  
                betweenUnit = number * unit * 1000;  
            }  
        }  
    }  

    return {  
        to : function (toUnit) {  
            if (betweenUnit) {  
                for (type in conversions) {  
                    if (conversions.hasOwnProperty(type)) {  
                        if ( (unit = conversions[type][toUnit]) ) {  
                            return fix(betweenUnit / (unit * 1000));  
                        }  
                    }  
                }  
                throw new Error("unrecognized to-unit");  
            } else {  
                throw new Error("unrecognized from-unit");  
            }    

            function fix (num) {  
                return parseFloat( num.toFixed(2) );  
            }  
        }  
    };  
}  

It puzzled me as to why/how it is used, and what's the reason for it. It appears to return an object, which is a labeled function (method really, according to JavaScript naming convention), which wouldn't be called or returned upon creation.

After pondering about this and running it in chrome dev tools, it hit me that being called Convert with a capital C, it might be used as a constructor that would be used with new (again, according to JavaScript naming convention) so I might create an object like:
var tenFeet = new Convert(10, 'feet'); and then use it as tenFeet.to('cm');.

This still makes no sense, since I wouldn't call the object (read: class) Convert, since it's not converting. I'd call the to method convertTo, and probably name Convert to Measurement or something.

  1. Is this simply bad code with bad naming, am I simply rooted too deeply in conventional OO and "formal" languages, or am I missing something basic?
  2. When / where / why would I use something like the above: "return labeled method" from an object in JavaScript?
  3. Couldn't the same be achieved by enhancing the prototype of Convert with the same method?

Cheers, and thanks in advance.

Upvotes: 0

Views: 617

Answers (2)

Noctis
Noctis

Reputation: 11773

Blender answered this correctly, but just in case other people stumble upon page, here's a little more info on what's happening.

Coming from more "formal" languages, I guess I was having issues with the "label" appearance of the to in the return statement.

from MDN on Label:

Summary
Provides a statement with an identifier that you can refer to using a break or continue statement.

For example, you can use a label to identify a loop, and then use the break or continue statements to indicate whether a program should interrupt the loop or continue its execution.

Syntax
label : statement

Do notice that if you're creating an object, the syntax is similar. For example:

person={firstname:"John",lastname:"Doe",age:50,eyecolor:"blue"};

This will result in an object looking like:

object {firstname: "John", lastname: "Doe", age: 50, eyecolor: "blue"}

Another note is that if you're creating an array, you'll just use the commas, like this:

person=["John","Doe",50,"blue"];

This will give an array looking like:

["John", "Doe", 50, "blue"]

It takes a bit of time to get used to JavaScript syntax and logic, but all that really happens in my example is that the function returns an object, that has a method (named to) defined on it.
Once you have that object, you can call the method on it using the usual dot notation, which results in the chaining that is used in the above case. Or reusing Blender's example:

Convert(10, 'meters').to('feet') === 32.81`

Upvotes: 0

Blender
Blender

Reputation: 298452

This is following the "read like a sentence" paradigm that some people like:

Convert(10, 'meters').to('feet') === 32.81
// Convert 10 meters to feet

You're right, the function goes against common naming conventions, but you can sort of guess that it shouldn't be created with the new keyword because there are no references to this in the function body.

This problem could've been avoided with proper documentation.

Upvotes: 1

Related Questions