Title Case a Sentence_Not Looping Through


#1

Just tips/pointers please. Trying to avoid spoilers. I have approached this problem in two ways, but neither is working. What areas do I need to read up on, look more carefully at, understand better, etc.? Thank you in advance.

function titleCase(str) {
  strArray = str.toLowerCase().split(' ');
    for (var i = 0; i < strArray.length; i++) {
    return strArray[i][0].replace(/[^A-Z]$/);
  }
return strArray.join(' ');
}
titleCase("I'm a little tea pot");

and

function titleCase(str) {
  str = str.toLowerCase().split(' ');
  for (var i = 0; i < str.length; i++) {
    return str[i][0].toUpperCase();
  }
  return str.join(' ');
}

titleCase("I'm a little tea pot");

#2

Respecting your wishes of not giving you a solution, I will explain what the 2nd solution is doing and it should help you understand also why the 1st solution is not working. I put comments within your code (below) to explain what is going on.

function titleCase(str) {
  str = str.toLowerCase().split(' ');  // after this line executes, str is now an array of non-capitalized words
  for (var i = 0; i < str.length; i++) { // loop to iterate through all elements of str
    return str[i][0].toUpperCase(); // on the first iteration of the loop, the return statement kicks out of the function and returns the uppercase I, which is the first letter of the first word (which coincidentally is an I)
  }
  return str.join(' '); // this line never executes, because after only one iteration in the loop, the function was exited via the 1st return statement
}

In your 1st solution, you have the line:

return strArray[i][0].replace(/[^A-Z]$/,'');

As in the 2nd solution, during the first iteration of the for loop, the function returns a value and exits the function completely. What is returned is undefined. You need to review the replace function and take note of the newSubStr (replacement) argument. You are not supplying this value.

Once you fix the items I have mentioned above, you are still going to have to add code to make each word in the strArray array capitalized, but I will let you figure that out. Let us know if you have any more questions or do not understand anything I have written here.


#3

You are misunderstanding the use of return. It exits you out of the function. When you get in your for loop the function stops running the second you get to return.

I think your second function is the closest.

A few things to think about:

  • In your for loop, is str.length really what you want to loop to? Also inside the function you keep referring to str - are you sure you don’t mean another variable?
  • When you assign the capitalized string (you’re going to need an equation), you remember that strings are immutable - they cannot be changed. You will need to construct the new string and assign it back onto itself. I recommend you look into the string.slice function

#4
  1. Your second attempt is closer to the money. The regex in your first attempt matches the character at the end of the string as long as it’s not an upper-case Latin letter, which isn’t what you want at all. In addition, the replace() method usually requires two arguments and you’ve only given one; because of this, it treats the second argument as undefined, which JavaScript then converts to the string 'undefined', giving rather strange results. For example:
    'abc'.replace(/[^A-Z]$/); // result is "abundefined"
    
  2. Confusingly, once line 2 executes, str is actually an array, because you reassigned* it to the value returned from split(), which takes a string and returns an array. Consider creating a new variable called splitUpInput or something.
  3. You aren’t doing anything with those returned values from your for loops — they just disappear into the ether.
  4. In any case, the returned values are just the first character of each string in your array. What you really want is the entire string, but with the first character upper case and the rest lower case. You can use the slice() method to get the rest of the string, and string concatenation in javascript is done with the + operator. A couple of hints for using these:
    'abcdef'.slice(2); // "cdef"
    'abc' + 'def'; // "abcdef"
    

*I’m actually not sure if this is a reassignment, because arguments are different from variables. I don’t know if this is reassigning the argument called str or creating a new variable called str. Either way, for practical purposes in your code, the result is the same.


#5

Two solutions satisfied the requirements. :slight_smile:

function titleCase(str) {
  strArray = str.split(' ');
  
  for (var i = 0; i < strArray.length; i++) {
    strArray[i] = strArray[i].slice(0,1).toUpperCase() + strArray[i].slice(1).toLowerCase();
  }
  return strArray.join(' ');
}

titleCase("I'm a little tea pot");
function titleCase(str) {
  var strArray = str.split(' ');
  for (var i = 0; i < strArray.length; i++) {
    strArray[i] = strArray[i].substring(0,1).toUpperCase() + strArray[i].substring(1).toLowerCase();
  }
  return strArray.join(' ');
} 

titleCase("I'm a little tea pot");

#6

It looks good. The only suggestion that I’d make is that strArray[i].slice(0,1).toUpperCase() might be a little cleaner as strArray[i][0].toUpperCase() - there’s no need to use slice or substring for one character.

But still, glad it worked out.


#7

If anyone’s interested, turns out that it does reassign the argument. What’s even more interesting (and a little alarming) is that properly declaring a variable of the same name using var does the same thing and doesn’t throw any errors. Luckily, the ES6 variable declaration keywords const and let both throw an error.

function reassignNoKeyword(num) {
  num = 2;
  console.log('num: ' + num + '; arguments[0]: ' + arguments[0]);
}

function reassignWithVar(num) {
  var num = 2;
  console.log('num: ' + num + '; arguments[0]: ' + arguments[0]);
}

function reassignWithConst(num) {
  const num = 2;
  console.log('num: ' + num + '; arguments[0]: ' + arguments[0]);
}

function reassignWithLet(num) {
  let num = 2;
  console.log('num: ' + num + '; arguments[0]: ' + arguments[0]);
}

reassignNoKeyword(1); // num: 2; arguments[0]: 2
reassignWithVar(1); // num: 2; arguments[0]: 2
reassignWithConst(1); // SyntaxError: Identifier 'num' has already been declared
reassignWithLet(1); // SyntaxError: Identifier 'num' has already been declared

// Because all of these either reassigns or throws an error, none
// of them leaks the variable into the global scope, which means:
console.log(num); // Uncaught ReferenceError: num is not defined

Speaking of JavaScript idiosyncrasies, substring and slice are mostly the same, but can behave somewhat differently with certain arguments. There’s a blog post here describing the differences, as well as another string method that’s confusingly named substr.


#8

let and const rule in my book - same with slice