4
\$\begingroup\$

I wrote a simple JavaScript SEO keyword counter. The user enters their SEO keyword in one field then enters their webpage text in a textarea field. It then calculates (in realtime, as the user types) how many times the keyword appears in the web page text. It also calculates the keyword density.

It works but probably is more complicated than it needs to be.

My code is as follows:

function myFunction() {
	
	var numberOfTimesKeyword = 0;
	
	// Prep the text ////////////////////////////////////
	// Remove all characters but a-z AND 0-9 AND spaces
	var pageText = textarea.value.replace(/[^\w\s]/gi, '');
	
	// Remove double spaces
	pageText = pageText.replace(/\s\s+/g, ' ');

	// Trim beginning and ending spaces
	pageText = pageText.trim();
	// End: Prep the text ////////////////////////////////////
	
	// Make textarea values into array
	var pageTextArray = pageText.split(" ");
	
	// Go through array and find out how many times the keyword appears
	for(var i in pageTextArray) {
		
		if (pageTextArray[i] == textfield.value) {
			numberOfTimesKeyword++;
		}
	
	}

	// Find keyword density
	var keywordDensity = (numberOfTimesKeyword / pageTextArray.length) * 100;	
	
	 if (numberOfTimesKeyword > 0) { // The keyword appears at least once
		 containsText.innerHTML = "The keyword appears <strong>" + numberOfTimesKeyword + "</strong> time(s).";
	 } else {
	 	containsText.innerHTML = "<strong>Does not contain keyword.</strong>";
	 }
	  
	 densityText.innerHTML = "<strong>Keyword Density ((# of times keyword appears / total words) * 100):</strong> " + Math.ceil(keywordDensity) + "%";
	 lengthText.innerHTML = "<strong>Array Length:</strong> " + pageTextArray.length;
}
<p>
<strong>SEO Keyword:</strong>
<br>
<input type="text" name="textfield" id="textfield" oninput="myFunction()">
</p>
<p>
<strong>Webpage Text:</strong>
<br>
<textarea name="textarea" cols="20" rows="5" id="textarea" oninput="myFunction()"></textarea>
</p>
<hr>
<p>
<span id="containsText"><strong>Does not contain keyword.</strong></span>
<br>
<span id="densityText"><strong>Keyword Density ((# of times keyword appears / total words) * 100):</strong> ---</span>
<br>
<span id="lengthText"><strong>Array Length:</strong> ---</span>
</p>

\$\endgroup\$

1 Answer 1

2
\$\begingroup\$
  1. Split your function into two parts: one which counts a keyword within a paragraph of text, and one which updates your HTML elements. These are different concerns. One is a pure function, and one is concerned with mutating the DOM to present results.
  2. Prefer clear code to comments. Remember that comments are just noise and visual clutter when the code itself is clear (which yours was). When you do want to add comments for extra clarity, keep them brief.
  3. Prefer functional method chaning to temporary variables, when possible.
  4. Use clear names rather than implementation details: Word count rather than Array Length.

function keywordStats(text, keyword) {
  
  var words      = text.replace(/[^\w\s]/gi, '') // only words and spaces
                   .replace(/\s\s+/g, ' ')       // remove double spaces
                   .trim()
                   .split(' '),
      wordCnt    = words.length,
      keywordCnt = words.reduce((m,x) => m + (x == keyword) ? 1 : 0, 0),
      density    = (keywordCnt / wordCnt) * 100;
  
  return { wordCnt, keywordCnt, density };
}

function updatePageStats() {
  var stats   = keywordStats(textarea.value, textfield.value),
      setHTML = (id, html) => document.getElementById(id).innerHTML = html;

  setHTML('containsText', 
    stats.keywordCnt
    ? "The keyword appears <strong>" + stats.keywordCnt + "</strong> time(s)."
    : "<strong>Does not contain keyword.</strong>");

  setHTML('densityText', 
    "<strong>Keyword Density ((# of times keyword appears / total words) * 100):</strong> " + Math.ceil(stats.density) + "%");

  setHTML('lengthText', 
    "<strong>Total Word Count:</strong> " + stats.wordCnt);
}
<p>
<strong>SEO Keyword:</strong>
<br>
<input type="text" name="textfield" id="textfield" oninput="updatePageStats()">
</p>
<p>
<strong>Webpage Text:</strong>
<br>
<textarea name="textarea" cols="20" rows="5" id="textarea" oninput="updatePageStats()"></textarea>
</p>
<hr>
<p>
<span id="containsText"><strong>Does not contain keyword.</strong></span>
<br>
<span id="densityText"><strong>Keyword Density ((# of times keyword appears / total words) * 100):</strong> ---</span>
<br>
<span id="lengthText"><strong>Word Count:</strong> ---</span>
</p>

\$\endgroup\$
2
  • \$\begingroup\$ +1 Thank you for your feedback and code revisions. I implemented most of your feedback but found that keywordCnt = words.reduce((m,x) => m + (x == keyword) ? 1 : 0, 0),caused the code to not work with Safari 9.1.1 (OS X 10.11.5). This also caused the code to not work with the code snippet you provided. It did work fine with Chrome & Firefox. The setHTML also caused the code to not work using Safari. \$\endgroup\$ May 17, 2016 at 23:16
  • \$\begingroup\$ I believe safaris ES6 support may be lacking \$\endgroup\$
    – Jonah
    May 17, 2016 at 23:24

Not the answer you're looking for? Browse other questions tagged or ask your own question.