Search code examples
javascriptprototypeextending

Sub functions of a function as a prototype


i'm trying to extend the Number object with a function that has two sub-functions. It works fine, except that the sub-functions can't access the Number object value via this and I don't figured out how to access it or if this is possible.

My code looks something like this

var currency = function(prefix) {
    var val = this.toString();
    prefix = prefix || 'R$';

    if(val > 99999) {
        val = val.replace(/(\d+)(\d{3})(\d{2})$/,prefix + " $1.$2,$3");
    } else if(val == 0) {
        val = prefix + ' 0,00';
    } else {
       val = val.replace(/(\d+)(\d{2})$/, prefix + " $1,$2");
    }
    return val;
};

currency.cents = function() {
    var val = this.toString();
    return val == 0 ? '00' : val.substring(val.length - 2);
};

currency.integer = function() {
    var val = this.toString();
    return val == 0 ? '0' : val.substring(0, val.length - 2);
};

Number.prototype.currency = currency; 

alert((12345).currency()); // "R$ 123,45"
alert((12345).currency.cents()); // return " }"

The problem is in the line "var val = this.toString();" because this refers to the function itself, not the value of the Number object.

Is there any way to accomplish this?

Second question: Why I need to put ( ) around the number 12345 for this to work? I'm not extending the number object and 12345 is not an instance of it?

Thanks in advance


Solution

  • It may not look as nice as what you are trying to do, but you could add all three methods directly to the prototype like this.

    var currency = function(prefix) {
        var val = this.toString();
        prefix = prefix || 'R$';
    
        if(val > 99999) {
            val = val.replace(/(\d+)(\d{3})(\d{2})$/,prefix + " $1.$2,$3");
        } else if(val == 0) {
            val = prefix + ' 0,00';
        } else {
           val = val.replace(/(\d+)(\d{2})$/, prefix + " $1,$2");
        }
        return val;
    };
    
    var currencyCents = function() {
        var val = this.currency();
        return val == 0 ? '00' : val.substring(val.length - 2);
    };
    
    var currencyInteger = function() {
        var val = this.currency();
        return val == 0 ? '0' : val.substring(0, val.length - 2);
    };
    
    Number.prototype.currency = currency;
    Number.prototype.currencyCents = currencyCents;
    Number.prototype.currencyInteger = currencyInteger;
    
    alert((12345).currency());         // R$ 123,45
    alert((12345).currencyCents());    // 45
    alert((12345).currencyInteger());  // R$ 123,
    

    And now for your second question..

    Why I need to put ( ) around the number 12345 for this to work? I'm not extending the number object and 12345 is not an instance of it?

    I found this question a lot trickier. I found the answer in Nick Craver's answer to Why don't number literals have access to Number methods? - it's because numbers can have decimals, so surround the number with parenthesis to make it clear that the period is for a function call and not for the decimal portion of the number.