I have recently carried out a test for university where I was given the following instructions:Write a simple JavaScript application that reads paragraphs of text  input by the user and creates a tabular list of all the words entered.  It should also display a count of words, commas and full stops below  the table.RequirementsThe user interface should consist of a textarea, button and results tableAccount for words and letters only, if the paragraphs contains any numbers then inform the user only words are allowed The application should accept a minimum of 5 words, a maximum of 500 wordsTreat standalone letters such as I and a as words Special characters such as ( 5 _  [ ] { }   $ &!% ! : ; \ / ) should either be ignored or treated as part of the word they sit  within.Commas and full stops should be countedThe following is the code I provided. I was told that the should have been modularised/separated out. I believed that the code was modularised as it I attempted to follow the Single Responsibility Principle. Can anyone provide any guidance as to how I could have improved this code?var app = app || {};(function() {  use strict;  var result,    arr;  app.initialize = {    init: function() {      app.runApp.init();    }  };  //Runs the application  app.runApp = {    init: function() {      $(.calculate).click(function() {        //Get input and remove all special characters and leading and trailing whitespace        var input = app.specialCharacters.remove($(.text-input).val().trim()).trim();        //Create an array from the input        arr = input.split( );        //Check there is not less than the min or more than max words and        //that the input does not contain numbers before building table.        if (app.minOrMax.init(arr) && !app.numberChecker.init(input)) {          app.removeErrors.init();          app.checker.init(arr, input);          //Full stops and commas removed at this point          arr = app.specialCharacters.removePunctuation(input).split( );          app.createWordHolder.init(arr);        }        //Add invalid class if there are too many/few words        if (!app.minOrMax.init(arr)) {          $(.number-error).css(display, none);          $(.minmax-error).fadeIn(1000);          app.errorHandler.init(arr, input);        }        //Add invalid class if there are numbers in the input        if (app.numberChecker.init(input)) {          $(.minmax-error).css(display, none);          $(.number-error).fadeIn(1000);          app.errorHandler.init(arr, input);        }      });    }  };  //Create an array to hold objects with a key containing the first   //letter of each word with a value of arrays containing their corresponding words   app.createWordHolder = {    init: function(array) {      result = [];      for (var i = 0; i < array.length; i++) {        var letter = array[i][0].toLowerCase();        if (typeof result[letter] == 'undefined') {          result[letter] = [];        }        result[letter].push(array[i]);      }      app.buildTable.init(result);    }  };  //Used to build the table from the result array  app.buildTable = {    init: function(result) {      var headers = Object.keys(result),        maxRows = 0,        rowsHtml = '';      //Sort the header in alphabethical order      headers.sort();      app.createHeaders.init(headers);      // Determine how many rows the table will have      for (var i = 0; i < headers.length; i++) {        if (result[headers[i]].length > maxRows) {          maxRows = result[headers[i]].length;        }      }      // Loop over the result array based on number or rows      for (var i = 0; i < maxRows; i++) {        //Create a new row on each loop        rowsHtml += '<tr>';        //Loop through each letter        //If the letter has an associated word add it to         //the row otherwise a blank td will be added        for (var j = 0; j < headers.length; j++) {          rowsHtml += '<td>';          if (i < result[headers[j]].length) {            rowsHtml += result[headers[j]][i];          }          rowsHtml += '</td>';        }        rowsHtml += '</tr>';      }      $(.words-header).after(rowsHtml);    }  };  //Used to build the header of the table  app.createHeaders = {    init: function(headers) {      // Empty the table in case of multiple tries      $(.words-header).parent().html('<tr class=words-header></tr>');      for (var i = 0; i < headers.length; i++) {        $(.words-header).append(<th> + headers[i].toUpperCase() + </th>);      }    }  };  //Count the number of commas and fullstops  app.punctuationCounter = {    commaCounter: function(input) {      var commaCount = (input.match(new RegExp(,, g)) || []).length;      $(.comma-count).text(, =  + commaCount);    },    fullStopCounter: function(input) {      var fullStopCount = (input.match(new RegExp(\\., g)) || []).length;      $(.fullstop-count).text(. =  + fullStopCount);    }  };  //Count the number of inputted words  app.wordCounter = {    init: function(sentence) {      $(.word-count).text(Words =  + sentence.length);    }  };  //Check if the input contains digits  app.numberChecker = {    init: function(sentence) {      return /\d/g.test(sentence);    }  };  //Check min or max number of words inputted  app.minOrMax = {    init: function(sentence) {      return (sentence.length < 5 || sentence.length > 500) ? false : true;    }  };  app.specialCharacters = {    //Remove special characters that are not included in a word    remove: function(sentence) {      return sentence.replace(/(?:^|\s+)\W+(?:\s+|$)/g,  );    },    //Remove commas and full stops at end of word    removePunctuation: function(sentence) {      return sentence.replace(/([a-z]+)\b[.,]/ig, '$1');    }  };  //Check word count, comma count and fullstop count  app.checker = {    init: function(arr, input) {      app.wordCounter.init(arr);      app.punctuationCounter.commaCounter(input);      app.punctuationCounter.fullStopCounter(input);    }  };  //Used to handle the UI following an input error  app.errorHandler = {    init: function(arr, input) {      $(.textarea-holder).addClass(invalid);      $(.words-header).parent().html('<tr class=words-header></tr>');      app.checker.init(arr, input)    }  };  //Used to remove error messages from UI  app.removeErrors = {    init: function() {      $(.minmax-error).css(display, none);      $(.number-error).css(display, none);      $(.textarea-holder).removeClass(invalid);    }  };  app.docOnReady = {    init: function() {      app.initialize.init();    }  };  $(document).ready(app.docOnReady.init);})(jQuery);html,body,div,span,h1,h2,h3,h4,h5,h6,p,a,img,ol,ul,li {  margin: 0;  padding: 0;  border: 0;  font-size: 100%;  font: inherit;  vertical-align: baseline;}body {  line-height: 1;  font-size: 14px;  background: #fff;  color: #00528e;  font-family: Helvetica, Arial, sans-serif;  font-weight: 400;  max-width: 1200px;  margin: 0 auto;}ol,ul {  list-style: none;}#main {  padding: 10px;}#main h1 {  font-size: 30px;  margin-bottom: 15px;  font-weight: 800;}#main .textarea-holder {  display: inline-block;  margin-bottom: 25px;}#main .textarea-holder.invalid {  border: 3px solid #ed0000;}#main .textarea-holder .text-input {  border: 3px solid #00528e;  padding: 5px;  color: #00528e;  font-family: Helvetica, Arial, sans-serif;  font-weight: 400;  font-size: 14px;  line-height: 20px;  letter-spacing: 0.5px;}#main .calculate {  display: block;  border: 1px solid #00528e;  text-transform: uppercase;  font-family: Helvetica, Arial, sans-serif;  font-size: 16px;  font-weight: 400;  text-transform: capitalize;  text-decoration: none;  color: #fff;  line-height: 20px;  letter-spacing: 0.5px;  max-width: 150px;  padding: 10px 10px;  background: #00528e;  border-radius: 0;  text-shadow: none;  box-shadow: none;  -webkit-box-shadow: none;  font-weight: 400;  margin-bottom: 25px;}#main .results-table table {  border-collapse: collapse;  margin-bottom: 15px;  width: 80%;}@media screen and (max-width: 768px) {  #main .results-table table {    width: 100%;  }}#main .results-table td,#main .results-table th {  border: 3px solid #00528e;  padding: .2em;  line-height: 20px;  letter-spacing: 0.5px;}#main .results-table .first-td {  display: none;}#main .results-table tr:nth-of-type(odd) {  background: #eee;}#main .error-messages .number-error,#main .error-messages .minmax-error {  display: none;  line-height: 20px;  letter-spacing: 0.5px;  margin-top: 25px;  width: 40%;}@media screen and (max-width: 768px) {  #main .error-messages .number-error,  #main .error-messages .minmax-error {    width: 100%;  }}/*# sourceMappingURL=style.css.map */<script src=https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js></script><div id=main>  <h1>Word Counter</h1>  <div class=textarea-holder>    <textarea class=text-input name=textarea rows=5 cols=30>The quick brown fox jumps over the lazy dog, before the duffle bag became his toy, now hes happy.</textarea>  </div>  <button class=calculate>Calculate</button>  <div class=results-table>    <table>      <tbody>        <tr class=words-header>          <td class=first-td></td>        </tr>      </tbody>    </table>    <p class=word-count></p>    <p class=comma-count></p>    <p class=fullstop-count></p>  </div>  <div class=error-messages>    <p class=number-error>Numbers cannot be entered. Please re-enter input without numbers.</p>    <p class=minmax-error>You have entered too few or too many words. Minimum amount of words accepted is 5, while the maximum number of words you may enter is 500. Please re-enter input with accepted amount of words.</p>  </div></div>
Counting and listing words in a table
javascript;jquery;object oriented