2

I have an application that can turns a tex file into a JavaScript object, with key-value pairs. The key being the word and the value being the number of times it has appeared in the text file. Let's go through it together:

FormatText.prototype.toDowncase = function() {
  return this._data = this._data.toLowerCase(); 
};

This turns the words to lowercase

FormatText.prototype.deleteWords = function() {
  return this._data = this._data.replace(/\W/g, " ");
};

This replaces all non-words with a space

FormatText.prototype.splitWords = function() {
  return this._data = this._data.split(/\s+/);
};

This turns the string in an array and splits at each delimiter

FormatText.prototype.filterEntries = function() {
  return this._data = this._data.filter(v => !!v);
};

This one above I have no clue what it does.

FormatText.prototype.countWords = function() {
  return this._data = this._data.reduce((dict, v) => {dict[v] = v in dict ? dict[v] + 1 : 1; return dict}, {});
}

Could someone explain this one, however I will get it a try:

This one takes the array and passed the method 'reduce' with two arguments. It counts how many times each individual word has appeared and returns an object with the 'key-value' pairs described at the beginning of this question.

  • 4
    `v => !!v` is essentially the `Boolean` function – MinusFour Jan 02 '18 at 17:52
  • `v => !!v` returns only those filter entries which are neither `0`, nor `""`, nor `false`, `null` or `undefined`. – connexo Jan 02 '18 at 17:54
  • Possible duplicate of [What is the !! (not not) operator in JavaScript?](https://stackoverflow.com/questions/784929/what-is-the-not-not-operator-in-javascript) – Alexander Jan 02 '18 at 18:05

4 Answers4

2

v => !!v means take v, and coerce it to a Boolean type by applying NOT twice. So the filter function is basically removing any falsey values (0, null, undefined) from this._data.

countWords is counting the number of times each word occurs in this._data - it is going through the array and adding 1 to the count if the word has been encountered before, or returning 1 if the word has not been encountered before. It returns an object with the words as keys and the counts as values.

As a note, these functions change the type of this._data, from a string, to an array, to an object. That may cause bugs to appear if e.g. you run the same method twice

Chris Applegate
  • 752
  • 3
  • 11
2

Why not just return the value, without NOT NOT, like

v => v

because for filtering the value coerces to a boolean value.

From Array#filter:

Description

filter() calls a provided callback function once for each element in an array, and constructs a new array of all the values for which callback returns a value that coerces to true. callback is invoked only for indexes of the array which have assigned values; it is not invoked for indexes which have been deleted or which have never been assigned values. Array elements which do not pass the callback test are simply skipped, and are not included in the new array.

Community
  • 1
  • 1
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
1

In this case the double exclamation mark is useless: the value returned from the callback in filter(callback) is then coerced to a boolean automatically, so no need to do it using double exclamation mark. The following lines are equivalent:

.filter(v => !!v)
.filter(v => v)
.filter(Boolean)
UndefinedBehavior
  • 836
  • 1
  • 11
  • 20
0

This one above I have no clue what it does.

The javascript operator ! (logical not) performs a type coercion (to boolean) on its argument. So applied twice you somehow convert any type to a boolean value which gives you whether it is falsy or truthy.

This is interesting when you want to apply a condition to different types whose semantic is more or less "no value". For example:

!!('') //false
!!(0) //false
!!null //false
!!undefined //false

Could someone explain this one, however I will get it a try

reduce is method of the array prototype which allows to iterate over a collection while aggregating value. In your specific example the aggregator is a dictionary which maps a word to a count (number of appearance). So if the word is not present in the dictionary it creates a key for this word with a counter initialized to 1 otherwise it increments the counter (if word already present).

A equivalent could be

const countWords = function (words = [], dictionary = {}) {

    if(words.length === 0) {
      return dictionary;
    } 

    const word = words.pop(); //remove and read the word at the end of the array
    if(word in dictionary) {//if key is present in the dictionary
       dictionary[word] += 1; // increment
    else {
       dictionary[word] = 1; // start a counter for new keyword
    }

    return countWords(words, dictionary);
}
laurent
  • 2,590
  • 18
  • 26