0

This function counts number of all characters of a string into a string. I am not fully understanding the if statement here and how it works.

function getFrequency(string) {
    var freq = {};
    for (var i=0; i<string.length;i++) {
        var character = string[i];
        if (freq[character]) {
           freq[character]++;
        } else {
           freq[character] = 1;
        }
    }

    return freq;
};

I thought freq[character] is the property of the object such as A B how does it work with if(freq[character]) also how does the increment of freq[character]++ works?

I have made test like this to try and understand it.

var v = {};
v.h = 3;
v["h"]++;
v["h"] = v["h"] + 1;
v.h++;
v.h = v.h + 2;
console.log(v);
console.log(v["h"]);

I think I can guess the if statement works that if the property exists but I thought JS has an object property calls .hasOwnProperty shouldn't this be used instead? As for the increments, to my test, it works but I just don't get the reason.

Can someone give me a hand to elaborate this? Thanks in advance

Dora
  • 6,776
  • 14
  • 51
  • 99
  • 1
    Looks like it's counting occurrences of characters `string = 'abbcccdd'` == `freq = [1,2,3,2]` – 8eecf0d2 Feb 16 '16 at 22:45
  • This counts the number of occurrences of each character (letter, number, etc) in a string. The if statement says essentially "if the [character] value of the freq object is set and has a value, then add one to it (that's what `++` does), otherwise set it to 1" – random_user_name Feb 16 '16 at 22:46
  • Welcome to JavaScript! [Have fun](http://stackoverflow.com/questions/7615214/in-javascript-why-is-0-equal-to-false-but-when-tested-by-if-it-is-not-fals) – Matthew Herbst Feb 16 '16 at 22:48
  • What exactly are you not understanding about the increment? `foo++` is imply a shorthand for `foo = Number(foo) + 1`. – Felix Kling Feb 16 '16 at 23:12
  • @FelixKling maybe I am just not thinking straight – Dora Feb 16 '16 at 23:22

3 Answers3

4

In javascript, objects are associative arrays. And vice versa. There is no difference between the two concepts.

So defining this variable as an empty object:

var freq = {};

... is actually creating an associative array (like a dictionary or map) with no keys added yet.

Moving on, let's take an input string like eek. The code here will look at the first letter and treat freq[character] the same as freq['e'], which is the same as freq.e.

In this code, the initial value of any letter in the freq object is undefined. So that initial if() check for the first "e" in our string actually looks like this:

if(undefined)

Javascript has the concept of "truthy" and "falsy" values; anything in javascript can be evaluated as a boolean, and (in most cases) a sensible result is achieved. Looking at undefined, Javascript will simply treat this a falsy value, fall to the else block, and therefore execute this code:

freq[character] = 1;

As already established, this is the same thing as freq.e = 1;

Now when the loop continues to the next letter (also an "e"), javascript will end up evaluating the expression if (1). Javascript treats this and all other non-zero numbers as "truthy", so this time will execute the following line:

freq[character]++;

Again, that's the same as freq.e++, where freq.e had a value of "1" that can now be incremented to "2".

One more time through the loop for the final letter "k". This time we get freq.k, which is still undefined. Undefined is falsy, so control falls to the else block, and freq.k is set to "1".

Now you can see how we can start to increment letters in the array as you find them in the string, even though it appears that you never defined an array in the first place, never set any values to anything other than "undefined", and never had a real boolean value to check against.

Joel Coehoorn
  • 399,467
  • 113
  • 570
  • 794
  • Wow thanks for the details, but this just got my curiosity about the `.hasOwnProperty` why do we still need this when if we can check it just like `if(object[property])` instead of using `if(object.hasOwnProperty['prop'])` – Dora Feb 16 '16 at 23:15
  • `.hasOwnProperty()` just returns a boolean. You _could_ use it, but it's more verbose. – Joel Coehoorn Feb 16 '16 at 23:19
  • This is off the topic, but wondering if this can be done without using objects and just returning like a list? Pretty much the same thing but not an object. – Dora Feb 16 '16 at 23:25
  • You'd need a dictionary or map, to **associate** specific letters with the count for that letter. Javascript does this via associative arrays, which again are they exact same thing as objects. In javascript, associative arrays and objects are just different ways to express in code the same underlying structure in memory. – Joel Coehoorn Feb 16 '16 at 23:27
  • Thanks you :D Guess I need more exercises which I am doing now :D – Dora Feb 16 '16 at 23:30
3

if (freq[character]) checks if the value is "truthy". That is, it's not false, null, undefined or 0. The first time we encounter any character the value will be undefined, since the object literal is created empty, so the "truthy" check will fail and control will fall to the else block.

So when we first see a specific letter set the value to 1 (which is now "truthy").

Any subsequent encounters of that letter just increment the value, which would be equivalent to say freq[character] = freq[character] + 1;. The increment syntax is just a shorthand.

Joel Coehoorn
  • 399,467
  • 113
  • 570
  • 794
Evan Trimboli
  • 29,900
  • 6
  • 45
  • 66
2

if (freq[character]) checks if the object freq has a property on it with the value of character as the name. The result of this expression evaluates to true or false.

It can be more explicitly stated, as the following non-exhaustively illustrates:

if (freq[character] == null)

or

if (typeof freq[character] === 'undefined')

The danger in not being explicit when evaluating if an object is undefined or null, is if it is actually set to a different type that evaluates to true or false (0, 1, '0', true, false).

lintmouse
  • 5,079
  • 8
  • 38
  • 54
  • `freq.character` is equivalent to `freq["character"]`. Property names after `.` are literals, not variables. – Barmar Feb 16 '16 at 22:51