Если кого-то еще интересует, что происходит в этой проверке:
При подстановке obj[array[i]] в условие, оно будет либо иметь значение undefined (если такого свойства в объекте нет), либо численное значение, когда оно там уже есть (1, 2, 3 и т.д., сколько раз оно нам встречалось).
Логический оператор !(отрицание) будет:
- Преобразовывать это значение к булевому типу: true/false.
undefined станет false, а численные значения (кроме 0) станут true;
- Возвращать противоположное значение.
Таким образом, если array[i] это свойство, которого объекте obj не существует, оно будет иметь значение undefined. При приведении к логическому типу оно станет false и затем отрицание вернет противоположное значение - true. А при if(true) выполняется тело условия -
obj[array[i]] = 1;
Свойство записывается в объект и ему присваивается значение 1.
Если же оно попадается нам снова. То при приведении к логическому типу
1 уже будет равно true.
Тогда оператор отрицания вернет в if противоположное значение -
if(false)
Соответственно, выполнится код в блоке else.
Можно сделать немного более понятно, избавившись от отрицания:
for( var i=0; i<array.length; i++ ){
if(obj[array[i]]) obj[array[i]]++; // Если свойство существует - прибавь 1.
else obj[array[i]] = 1; // В других случаях - создай со значением 1.
}