0

Here is the code

converter = 
{
    'SIToImperial' : 
    {
        'cm'    : function(value) {return value * convertRatioImperial[0];},
        'm'     : function(value) {return value * convertRatioImperial[1];},
        'km'    : function(value) {return value * convertRatioImperial[2];},
        'g'     : function(value) {return value * convertRatioImperial[3];},
        'kg'    : function(value) {return value * convertRatioImperial[4];},
        't'     : function(value) {return value * convertRatioImperial[5];},
        'mL'    : function(value) {return value * convertRatioImperial[6];},
        'L'     : function(value) {return value * convertRatioImperial[7];},
        'm3'    : function(value) {return value * convertRatioImperial[8];},
        'kWh'   : function(value) {return value;},
        'nb'    : function(value) {return value;},
        'undefined': function(value) {return 'Not Found';}
    }
}

It is clear that my line 'undefined'.... does not work like I want it to.

I would like that when converter["SIToImperial"][units] is called with an 'units' not listed in the properties. Exemple : converter["SIToImperial"]['oz']. It should return the undefined line IE 'Not Found'.

Could someone help me out I have tried various ways but I'm still not enough familiar with dictionnaries to get it working properly.

Update :

//Generalized conversion function
function convert(value,valueUnit,system, toSI)
{
    var result;
    //From SI to Imp/U
    if(!toSI)
    {
        result = converter.guardian('SITo'+system,valueUnit,value);
    }
    else if(toSI)//To SI from Imp/US
    {
        result = converter.guardian(system+'ToSI',valueUnit,value);
    }
    return result;
};

and

converter = 
{

    guardian    :   function (system,units,value) {var label = this[system][units]; if(typeof(label) === 'undefined') {return "Not Found";} else {return label(value);}},
    'SIToImperial' : 
    {
        'cm'    : function(value) {return value * convertRatioImperial[0];},
        'm'     : function(value) {return value * convertRatioImperial[1];},
        'km'    : function(value) {return value * convertRatioImperial[2];},
        'g'     : function(value) {return value * convertRatioImperial[3];},
        'kg'    : function(value) {return value * convertRatioImperial[4];},
        't'     : function(value) {return value * convertRatioImperial[5];},
        'mL'    : function(value) {return value * convertRatioImperial[6];},
        'L'     : function(value) {return value * convertRatioImperial[7];},
        'm3'    : function(value) {return value * convertRatioImperial[8];},
        'kWh'   : function(value) {return value;},
        'nb'    : function(value) {return value;}
    }
}
MatthewMartin
  • 29,993
  • 30
  • 102
  • 160
Fawar
  • 735
  • 1
  • 11
  • 31
  • Why don't you make SIToImperial function that takes this as parameter - it even makes more sense to call converter.SIToImperial('cm', 2) then converter['SIToImperial']['cm'](2) or converter.SIToImperial['cm'](2) or converter.SIToImperial.cm(2) – Hurda Jul 30 '13 at 15:35
  • I have a wrapping function over it, because I wrap from View to Model and from Model to View. When I call the wrapper it look like this convertToView(value,unit) or convertToModel(value,unit) – Fawar Jul 30 '13 at 16:13

3 Answers3

1

Not a really nice solution but quick and easy:

var my_conv = converter.SIToImperial[units] || converter.SIToImperial["undefined"];
console.log(my_conv(value));

Side note:

converter[SIToImperial] // is probably wrong, you either mean:
converter["SIToImperial"] // or
converter.SIToImperial
Halcyon
  • 54,624
  • 10
  • 83
  • 122
  • You are right i meant converter["SIToImperial"] and converter.SIToImperial – Fawar Jul 30 '13 at 16:04
  • That way of testing it is outside the object, so I would need to put that if everywhere in my code, plus I'm pretty sure that is would crash before returning my_conv since if the unit is not defined it generates an error, so no result would ever be returned to do the if-clause – Fawar Jul 30 '13 at 16:11
  • @Fawar: How would `units` not be defined? We though your problem was that `units` is defined but has a value for which your object has no property. – Bergi Jul 30 '13 at 17:43
  • @Fawar: As I said in my answer, you always need to test outside of the object - there's no other way, and all three posted answers do it. – Bergi Jul 30 '13 at 17:45
  • You are right on the problem I had. I misexplained what I mean in my comment. Sorry. I wanted to test inside the converted object, seen updated details on how I did it. – Fawar Jul 30 '13 at 17:53
1

I don't believe there is a way to achieve your goal here. You are essentially trying to hook the case where a member is asked for that doesn't exist. Such a hook doesn't exist in javascript. Instead I think you'll need to use a function here that wraps the type

converter = 
{
    'SIToImperial' : 
    {
        ... 
        getMember = function (name) {
          var value = this[name];
          if (typeof(value) === 'undefined') { 
            return 'Not Found'
          }
          return value;
    }
}
JaredPar
  • 673,544
  • 139
  • 1,186
  • 1,421
  • Using your solution, I would need to add a function that would be test the unit received before accessing it if it exists? Is that it. In the current situation, it would mean that every single call I have done to that structure would need an update to go through that "wrapping" function. It would work but in my situation I doubt it the good way to do it has i'm not "starting" to use that system, it is already been used alot. – Fawar Jul 30 '13 at 16:10
  • @Fawar your analysis is correct. However i think you will need some manner of updating here. There is simply no way to hook the missing value case in a `[]` expression. If you want the solution to be universal it will involve changing of all call sites one way or the other – JaredPar Jul 30 '13 at 16:14
  • Damn, i hoped that it would not come to this. I'll see how I could bypass this problem, since I already have some wrapper, one might fit well to easily add your solution inside this object – Fawar Jul 30 '13 at 16:20
  • @Fawar: If you already have a wrapper, you can easily integrate it there. There's no need to put a method on each data object. – Bergi Jul 30 '13 at 17:41
  • The object is never instantiated, it's kind of a static-library object. – Fawar Jul 30 '13 at 17:53
0

You can't do that. Instead of defining a "default" property on the object, you have to set up a default behaviour for when accessing the object fails. You don't even need a guardian method, you can do it right in the convert function:

function convert(value,valueUnit,system, toSI) {
    return ( converter[ toSi 
               ? system+'ToSI'
               : 'SITo'+system
             ][valueUnit]
           || function() {
                  return 'Not Found';
              }
           ) (value);
}

or

function convert(value,valueUnit,system, toSI) {
    var units = converter[ toSi ? system+'ToSI' : 'SITo'+system ];
    return valueUnit in units
            ? units[valueUnit](val)
            : 'Not Found';
}
Community
  • 1
  • 1
Bergi
  • 513,640
  • 108
  • 821
  • 1,164
  • I am not quite sure to understand the semantic on the 2nd code exemple? Looks like an if to me but I never ever used it that way ? :O Anyway, it holds the same problem as Fritz Van Campen's answer – Fawar Jul 30 '13 at 16:08