0

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.

0

2 Answers 2

1

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.

Sign up to request clarification or add additional context in comments.

1 Comment

You ser, have the gist of it. Once you said "chaining", a quick look on google got me on my feet. You actually do the same in C# when using linq, but I guess it is abstracted away so it wasn't as obvious.
0

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`

1 Comment

The label syntax has nothing to do with this. JavaScript (sadly) doesn't distinguish data types when they are keys in objects, so {to: 2} and {'to': 2} are exactly the same. That function just returns an object, whose to property can be accessed with .to and the returned function can then be called.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.