0

I'm doing a class on javascript this semester, and one of this week's exercises was to take a string of words, and capitalize the first letter of each word. I did that using .map(), the code is here :

let t1 = "hello how are you doing".split(" ");

let t2 = t1.map(function(word) {
  return word[0].toUpperCase() + word.slice(1);
});
console.log(t2.join(" "));

And it works perfectly fine. However, I was wondering why, when I try with forEach(), I can't make it work. Here is my code :

let t1 = "hello how are you doing".split(" ");


t1.forEach(function(word) {
  word[0] = word[0].toUpperCase();
})
console.log(t1.join(" "));

My understanding of forEach() is that it cycles through every element of the table, much like a simple for loop. So then shouldn't my code take the first letter of each word, and replace it with the same letter, to which toUpperCase() is applied?

edit : I already know how to capitalize the first letter of each word, I was just asking about the different methods

Arnaud Stephan
  • 406
  • 3
  • 16
  • Possible duplicate of [Convert string to title case with JavaScript](https://stackoverflow.com/questions/196972/convert-string-to-title-case-with-javascript) – nikamanish Nov 22 '17 at 13:05
  • 4
    @nikamanish No. Its not a dupe. OP knows how to do it. Question is why `forEach` approach is not working – Rajesh Nov 22 '17 at 13:05

3 Answers3

2

let word = 'foo';
word[0] = 'F';
console.log(word);

The modification of word doesn't take because strings are immutable. You can't change a single character inside a string.

For character access using bracket notation, attempting to delete or assign a value to these properties will not succeed. The properties involved are neither writable nor configurable.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String

Community
  • 1
  • 1
deceze
  • 510,633
  • 85
  • 743
  • 889
2

First, string in JS is immutable.

var str = 'hello World';
str[0] = 'H';
console.log(str)

So word[0] = will not have any effect.

Second, even if it was, you are updating a value of an argument variable and not value in array.

var a = [1, 2, 3];

a.forEach(function(n) {
  n = n * 2;
});

console.log(a)

As per discussion with @deceze, this point is not accurate.

If a string was mutable, that would have worked just fine. Your "Second" doesn't really apply. – deceze


@deceze Objects are assigned using reference, so it will have the effect. Primitive values are assigned using value. So n in my understanding will always be a copy of item in array. Any manipulation relating to it should not affect the item in array. And string being a primitive value, I mentioned it. Also, I can't think of any variable that has property and is of primitive type. If you have any idea please let me know. Would be glad to learn. :-) – Rajesh


Sure, you're right about that. That's why I'm saying if it was mutable in the first place… Since it's not, the point is moot either way. – deceze


To get the desired effect, you will have to override value in array.

let t1 = "hello how are you doing".split(" ");


t1.forEach(function(word, index) {
  t1[index] = word[0].toUpperCase() + word.substring(1);
})
console.log(t1.join(" "));

Reference:

Community
  • 1
  • 1
Rajesh
  • 24,354
  • 5
  • 48
  • 79
  • If a string was mutable, that would have worked just fine. Your "Second" doesn't really apply. – deceze Nov 22 '17 at 13:12
  • That snippet doesn't prove anything as it's not doing the same thing. `n = ` (assignment to local variable) is different from `n[0] = ` (assignment to property of object). – deceze Nov 22 '17 at 13:16
  • @deceze Objects are assigned using reference, so it will have the effect. Primitive values are assigned using value. So `n` in my understanding will always be a copy of item in array. Any manipulation relating to it should not affect the item in array. And string being a primitive value, I mentioned it. Also, I can't think of any variable that has property and is of primitive type. If you have any idea please let me know. Would be glad to learn. :-) – Rajesh Nov 22 '17 at 13:22
  • Sure, you're right about that. That's why I'm saying ***if it was mutable*** in the first place… Since it's not, the point is moot either way. – deceze Nov 22 '17 at 13:25
1

So then shouldn't my code take the first letter of each word, and replace it with the same letter, to which toUpperCase() is applied?

Because word is a primitive value hence when you set new value to word, it doesn't carry the reference back to the array.

However, if parameter of forEach is not a primitive value, then the original one gets mutated, see the demo below

var arr = [[1,2,3],[4,5,6],[7,8,9]];
arr.forEach(function(item){
  item.push(1);
})
console.log(arr);
gurvinder372
  • 66,980
  • 10
  • 72
  • 94