-2

I am really new to this kind of programming and i have a block of code which i have some questions about.

Code:

function numFormat(n) {
    return n.toFixed(0).replace(/./g, function(c, i, a) {
        //console.log(a);
        return i > 0 && c !== "." && (a.length - i) % 3 === 0 ? "," + c : c;
    });
}

I actually do know what it does, it turns a number for example 1234 to 1,234 divides in groups of 3 with a "," for currency figures.

I really do not understand how it does it. I dont know from where c i and a are being filled with what and from where!?

Can please somebody explain to me this function?

Thanks and Regards

Gabriele Petrioli
  • 191,379
  • 34
  • 261
  • 317
Combinu
  • 882
  • 2
  • 10
  • 31
  • 1
    [String.prototype.replace()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace) – emerson.marini Jan 14 '15 at 20:44
  • possible duplicate of [How do JavaScript closures work?](http://stackoverflow.com/questions/111102/how-do-javascript-closures-work) – Ryan Jan 14 '15 at 20:44
  • I have read that one but i cant still seem to find what i am looking for, still i dont get where c i and a are getting from! – Combinu Jan 14 '15 at 20:48
  • @ryan Not strictly closure. The callback doesn't use any variables from outer scope and could just as well be declared elsewhere. `c`, `i` and `a` are just function arguments. – GolezTrol Jan 14 '15 at 21:26

2 Answers2

1

Quick overview:
For every character in the given input

return n.toFixed(0).replace(/./g, function(c, i, a) {

Execute the following ternary:

return i > 0 && c !== "." && (a.length - i) % 3 === 0 ? "," + c : c;

Which can simply be written as

if (i > 0 && c !== "." && (a.length - i) % 3 === 0) {
    return "," + c;
} else {
    return c;
};

The arguments c, i and a are as outlined in the spec, namely:

  • c is the matched substring, that is, a single character of the input
  • i is the offset of the matched substring, in this context meaning the index of the char we're currently working with
  • a is the total string being examined

Combining all this we can reword

if (i > 0 && c !== "." && (a.length - i) % 3 === 0) {
    return "," + c;
} else {
    return c;
};

as

If we're not looking at the first character of the input
and
if the character we're looking at is not a dot
and
if the current index of the examined char is divisible by three (since we want to separate every three chars)
then insert a comma followed by the current character,
otherwise replace that character with itself.

Sevle
  • 3,109
  • 2
  • 19
  • 31
Etheryte
  • 24,589
  • 11
  • 71
  • 116
  • 1
    Mind updating your answer to include the function portion of the `replace` function and what that function accepts as parameters? That seems to be where the OP has some confusion. – Anthony Forloney Jan 14 '15 at 20:48
  • Ok i get that part but what variables are being passed to c, i and a? – Combinu Jan 14 '15 at 20:51
1

Replace

The replace function accepts a regular expression, and replaces each match with a value. The replacement value is determined by the function you pass to replace as the second argument.

Anonymous functions as callbacks

The anonymous function is not (visibly) called from the JavaScript code, but is called internally by the replace function. You don't pass the function result but the function itself to replace, so replace can call your function to process the matches. This way you can 'inject' behaviour into JavaScript's built-in functions. This is a common concept in JavaScript, and you'll encounter this on many occasions.

The '.' wildcard in the pattern

So, the function is called for each match of the pattern. The core of this pattern is the dot . character. It is a wildcard meaning 'any character'. So any character in the given number is matched by the dot. The effect of this, is that the function is called for each separate character in the number.

Arguments and inner workings of the callback

Then the arguments a, c and i. The meaning of the arguments of the callback function are of course documented for the replace function, but it may become a bit clear at once if you output c, i and a to the console as I've done in the snippet below.

function numFormat(n) {
return n.toFixed(0).replace(/./g, function(c, i, a) {
    console.log(a + ',' + i +',' + c);
    return i > 0 && c !== "." && (a.length - i) % 3 === 0 ? "," + c : c;
});
}

alert(numFormat(107784));

The parameters of the function are the matched substring (c), which is one character each time (as matched by the pattern), the offset/string position (i) of the match, and the whole string (a).

Using the offset i, a calculation is made to see if it is the third character or not. If so, the character c is returned with a comma in front of it, otherwise, just the character is returned. i > 0 is added as an extra condition to prevent a comma at the start of the string. c !== "." seems to be obsolete and may be a leftover from an attempt to support floating point numbers as well.

All these returned strings are put back together (again, internally by replace) and will form the return value of the replace function.

Additional documentation

GolezTrol
  • 114,394
  • 18
  • 182
  • 210
  • Ok i have seen the console but still cant get what variable is being passes to c, i and a and from where? I mean for function numFormat you are passing (107784) into n but what is passed in c i and a – Combinu Jan 14 '15 at 20:56
  • @MysticJay Why don't you stick some `console.log()` and check them? – emerson.marini Jan 14 '15 at 20:58
  • 1
    @MysticJay The [`replace`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace#Specifying_a_function_as_a_parameter) section on the MDN page goes into detail about the function arguments. When passing a `function` as a second argument into `replace`, the first argument (ie, `c`) is the match substring (ie, `107784` in the above case), second argument (ie, `i`) is the *n-th* position in the match substring (ie, `0` for first iteration, `1` for second iteration, etc.) while the last (ie, `a`) is the current value on that iteration. – Anthony Forloney Jan 14 '15 at 21:00
  • @MysticJay I've added some more context and structure and a part about callbacks. – GolezTrol Jan 14 '15 at 21:28