1

I’m trying to write a function that takes a string and capitalizes the first letter in each word that is not included in the “minorWords” string. What is missing in my code that causes the return value to be “undefined”? After writing this function a few different ways I am now thinking that I am just using .forEach incorrectly. I am fairly certain that I am using the ternary operator appropriately, but I tried substituting an if statement and got the same result ( undefined ). I am also not sure why undefined is being returned twice . . .

function titleCase1(title, minorWords) {
  var titleArray = title.split(" ");
  var minorArray = minorWords.split(" ");
  var newArray = titleArray.forEach(function(word){
    (word in minorArray)? word : 
       word[0].toUpperCase() + word.slice(1);
  })
  console.log(newArray);
}

titleCase1("the wind in the willows", "the in");
// -> undefined undefined

I realize that if this works the first "the" will not be capitalized, but I will figure that out once I am no longer misusing the tools I have here . . .

swoopedj
  • 115
  • 2
  • 12
  • 1
    That’s because you don’t do anything with `word` or `word[0].toUpperCase() + word.slice(1)`. You probably meant `map` instead of `forEach` and forgot to `return` the value. – Sebastian Simon Aug 30 '15 at 15:00
  • 1
    Take a look at: http://stackoverflow.com/questions/4878756/javascript-how-to-capitalize-first-letter-of-each-word-like-a-2-word-city – jwkicklighter Aug 30 '15 at 15:01
  • 1
    And `undefined` isn’t returned twice, it’s returned once and _logged_ once. You don’t have a `return` statement in `titleCase1` either. – Sebastian Simon Aug 30 '15 at 15:01
  • Replaced .forEach with .map and added return before the ternary condition and solved the problem i was having, though (word in minorArray ) is evaluated as false for each word and they are all coming out capitalized, which is a different issue . . . – swoopedj Aug 30 '15 at 16:15

1 Answers1

2

There're two problems with your code:

  1. The only thing forEach does is execute a callback for each element in an Array and does NOT return anything, therefore newArray will always be undefined. For reference check how forEach works here.

    If you want to create a new Array with values like how you're trying to do with newArray. You need to use map, but you actually require to return a value from the callback. For reference check how map works here.

  2. You can't use the in operator to see if a word is present in your Array. The in operator only checks if a specified property is present in a specified Object. Therefore it will always return false when used for checking an element inside of an Array. Because an Array in javascript is actually an Object under the hood!

    var a = [ 'a', 'b', 'c' ];

    is actually

    var a = { 0: 'a', 1: 'b', 2: 'c' };

    Therefore 'a' in [ 'a', 'b', 'c' ] will always return false and for example 0 in [ 'a', 'b', 'c' ] will return true.

    Because of this caveat you should change your approach and for example use indexOf. For reference check how indexOf works here.

With this in mind you could modify your code to the following to get the desired behaviour:

function titleCase1(title, minorWords) {
  var titleArray = title.split(' ');
  var minorArray = minorWords.split(' ');
  var newArray = titleArray.map(function (word) {

    // indexOf returns the elements index on match or -1.
    var match = minorArray.indexOf(word) != -1;

    // If there's a match, return the (lowercased) word, otherwise uppercase it.      
    return match ? word : (word[0].toUpperCase() + word.slice(1));
  });

  console.log(newArray);
}

titleCase1("the wind in the willows", "the in"); // [ 'the', 'Wind', 'in', 'the', 'Willows' ]
danillouz
  • 6,121
  • 3
  • 17
  • 27