Capitalize the first letter of each word using - javascript

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

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:
Are JavaScript strings immutable? Do I need a "string builder" in JavaScript?

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

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);

Related

When do I need to create a new variable within a function?

I'm a new learner of JavaScript, and when I get to learn the way of using a function. It sometime confuses me on why we should declare a new variable and add the variable to the action we want to execute. Let's look into the code.
function reverse(word){
Array.from(word);
let reverseWord='';
for(i = word.length-1; i >= 0; i--) {
reverseWord += word[i];
}
return reverseWord;
}
I'm sure you know this one of the way of reversing string in javascript, my question is:
Why do we need to declare a new variable within the function, when should we declare it?
Why can't I just type console.log(word[i]);?
What does it mean by wordLength+=word[i];?
Why should we return the new variable(wordLength), instead of the function(reverse) after the loop?
Why do we need to declare a new variable within the function...
Because you need a place to store the reversed word as you build it. (Note: wordLength isn't a good name for that variable. It doesn't contain the word's length. It contains the characters of the reversed word.)
...when should we declare it?
Any time before you first need it.
Why can't I just type console.log(word[i]);?
Because the goal of the exercise is to build a string containing the reversed word, not just to output it. (And because console.log writes a new line each time you call it.)
What does it mean by wordLength+=word[i];?
That adds the character in word[i] to the end of wordLength. For instance, if the word is "start", wordLength starts out with "", then gets "t" added to it to make it "t", then gets "r" added to it to make "tr", and so on.
(+= is a shorthand way to write wordLength = wordLength + word[i];. There are several of these compound assignment operators, most of them for math: -=, *=, etc.)
Side note: The Array.from call in your code isn't doing anything useful. It's creating an array, but then throwing that array away because nothing uses the return value. The rest of the code is using the string you receive in word.
Why do we need to declare a new variable within the function, when should we declare it?
Vars is a place to store data. If your algorithm requires keeping some data to use it later you need vars. Also well named variables is a good way to create easy-to-understand code
Why can't I just type console.log(word[i]);?
You can, but it will do nothing useful. Your goal is to build a string and return it. Usage of your function will be something like
const word = getSomeText()
const reversedText = reverse(word)
doSomeStuff(reversedText) // whatever, send it online, or render it on screen some fancy way, not in the console.
So you need to return actual string, not to solve a puzzle and show the answer whatever way you like
Why should we return the new variable(wordLength), instead of the function(reverse) after the loop?
Because it contains reversed word and you function supposed to return it. there is rare complicated occasions when a function returning itself is useful, but it has nothing in common with your task
Why do we need to declare a new variable within the function, when should we declare it?
Variable is required to store the data value that can be changed later on. In your case wordLength variable is required to store the reverse string.
It's best to declare variables when you first use them to ensure that they are always initialized to some valid value.
Why can't I just type console.log(word[i])
console.log() is used just to print the output but will not use if you want to return something and as per your statement it will just print the word[i] not a whole reverse string.
What does it mean by wordLength+=word[i]
It means you are concatenating the each iteration word[i] into a wordLength variable.
wordLength+=word[i] is a shorthand for wordLength = wordLength + word[i]. If the left hand side of the + operator is a string, JavaScript will coerce the right hand side to a string.
Why should we return the new variable(wordLength), instead of the function(reverse) after the loop ?
Because this is what you expected from the function. It returns the reversed string and function should return it.

Iterate over RegExp.exec(...)

From the RegExp.exec page on MDN, it gives the following example of iterating through a match with the g flag set:
const regex1 = RegExp('foo*', 'g');
const str1 = 'table football, foosball';
let array1;
while ((array1 = regex1.exec(str1)) !== null) {
console.log(`Found ${array1[0]}. Next starts at ${regex1.lastIndex}.`);
// expected output: "Found foo. Next starts at 9."
// expected output: "Found foo. Next starts at 19."
}
I have two questions about this code. The first one is why the !=== null is used here, why wouldn't the while loop be properly coded as:
while (array1 = regex1.exec(str1)) { // implicitly casts to boolean?
console.log(`...`);
}
The above seems much more readable to me, but was wondering why the MDN docs used the first approach? Second, is it possible to declare and define the variable directly in the while loop? Something like:
while (let array1 = regex1.exec(str1)) { // don't need the `let array1` above?
console.log(`...`);
}
Or is that not supported in the JS language?
Why the !== null is used here...?
True, in this case it is not needed. .exec() returns either an array or null, and since arrays are always truthy there is no need to explicitly compare with null.
Is it possible to declare and define the variable directly in the while loop?
No. If you want that, then turn to the for loop, which does support this:
for (let array1; array1 = regex1.exec(str1); null) {
console.log(`...`);
}
This does indeed have the advantage that array1 has a more restricted scope. NB: I provided null to stress that the third part of the for header is intentionally unused.

Using "OR" operator inside includes() to trial the existence of any substrings within a string?

I noticed when trying to use OR operators inside an includes() function like this
x.includes("dogs"||"cats"||"birds"||"fish"||"frogs")
It will only trial the first string contained, and no further. I suspect that i'm either missing something obvious here or includes() isn't the right function to be used for this kind of situation.
The goal is to trial multiple strings to determine if they are substrings of x. Because i'm trying to use or operators, my intent is to not receive an array of boolean values for each trial string, but rather if any are true, then a single boolean value of true, otherwise false is desired.
The || operator is not distributive. Function arguments are simply evaluated as expressions, so your call is equivalent to:
var temp = "dogs"||"cats"||"birds"||"fish"||"frogs";
x.includes(temp)
The value of a series of || operations is the first truthy value in the series. Since all non-empty strings are truthy, that's equivalent to:
var temp = "dogs";
x.includes(temp)
You need to use || on the result of calling includes for each string:
x.includes("dogs") || x.includes("cats") || x.includes("birds") ...
You can simplify this by using the some() method of arrays:
["dogs","cats","birds","fish","frogs"].some(species => x.includes(species))
includes only looks for one string. You can use .matchAll() function which returns an iterator of all matching results
const regex = /dogs|cats|birds|fish|frogs/g;
const str = 'the dogs, cats, fish and frogs all watched birds flying above them';
const exists = [...str.matchAll(regex)].length > 0;
console.log(exists);
For this case, with a regular expression and a wanted boolean result RegExp#test comes in handy.
This approach does not return an iterator and need no array for getting a length of it.
const
regex = /dogs|cats|birds|fish|frogs/g,
str = 'the dogs, cats, fish and frogs all watched birds flying above them',
exists = regex.test(str);
console.log(exists);
Here's what I use in this situation:
let searchString = "fish"
console.log(["dogs","cats","birds","fish","frogs"].includes(searchString))

Regex to define the number of appearances substituted [duplicate]

I'd like to know how to replace a capture group with its uppercase in JavaScript. Here's a simplified version of what I've tried so far that's not working:
> a="foobar"
'foobar'
> a.replace( /(f)/, "$1".toUpperCase() )
'foobar'
> a.replace( /(f)/, String.prototype.toUpperCase.apply("$1") )
'foobar'
Would you explain what's wrong with this code?
You can pass a function to replace.
var r = a.replace(/(f)/, function(v) { return v.toUpperCase(); });
Explanation
a.replace( /(f)/, "$1".toUpperCase())
In this example you pass a string to the replace function. Since you are using the special replace syntax ($N grabs the Nth capture) you are simply giving the same value. The toUpperCase is actually deceiving because you are only making the replace string upper case (Which is somewhat pointless because the $ and one 1 characters have no upper case so the return value will still be "$1").
a.replace( /(f)/, String.prototype.toUpperCase.apply("$1"))
Believe it or not the semantics of this expression are exactly the same.
I know I'm late to the party but here is a shorter method that is more along the lines of your initial attempts.
a.replace('f', String.call.bind(a.toUpperCase));
So where did you go wrong and what is this new voodoo?
Problem 1
As stated before, you were attempting to pass the results of a called method as the second parameter of String.prototype.replace(), when instead you ought to be passing a reference to a function
Solution 1
That's easy enough to solve. Simply removing the parameters and parentheses will give us a reference rather than executing the function.
a.replace('f', String.prototype.toUpperCase.apply)
Problem 2
If you attempt to run the code now you will get an error stating that undefined is not a function and therefore cannot be called. This is because String.prototype.toUpperCase.apply is actually a reference to Function.prototype.apply() via JavaScript's prototypical inheritance. So what we are actually doing looks more like this
a.replace('f', Function.prototype.apply)
Which is obviously not what we have intended. How does it know to run Function.prototype.apply() on String.prototype.toUpperCase()?
Solution 2
Using Function.prototype.bind() we can create a copy of Function.prototype.call with its context specifically set to String.prototype.toUpperCase. We now have the following
a.replace('f', Function.prototype.apply.bind(String.prototype.toUpperCase))
Problem 3
The last issue is that String.prototype.replace() will pass several arguments to its replacement function. However, Function.prototype.apply() expects the second parameter to be an array but instead gets either a string or number (depending on if you use capture groups or not). This would cause an invalid argument list error.
Solution 3
Luckily, we can simply substitute in Function.prototype.call() (which accepts any number of arguments, none of which have type restrictions) for Function.prototype.apply(). We have now arrived at working code!
a.replace(/f/, Function.prototype.call.bind(String.prototype.toUpperCase))
Shedding bytes!
Nobody wants to type prototype a bunch of times. Instead we'll leverage the fact that we have objects that reference the same methods via inheritance. The String constructor, being a function, inherits from Function's prototype. This means that we can substitute in String.call for Function.prototype.call (actually we can use Date.call to save even more bytes but that's less semantic).
We can also leverage our variable 'a' since it's prototype includes a reference to String.prototype.toUpperCase we can swap that out with a.toUpperCase. It is the combination of the 3 solutions above and these byte saving measures that is how we get the code at the top of this post.
Why don't we just look up the definition?
If we write:
a.replace(/(f)/, x => x.toUpperCase())
we might as well just say:
a.replace('f','F')
Worse, I suspect nobody realises that their examples have been working only because they were capturing the whole regex with parentheses. If you look at the definition, the first parameter passed to the replacer function is actually the whole matched pattern and not the pattern you captured with parentheses:
function replacer(match, p1, p2, p3, offset, string)
If you want to use the arrow function notation:
a.replace(/xxx(yyy)zzz/, (match, p1) => p1.toUpperCase()
Old post but it worth to extend #ChaosPandion answer for other use cases with more restricted RegEx. E.g. ensure the (f) or capturing group surround with a specific format /z(f)oo/:
> a="foobazfoobar"
'foobazfoobar'
> a.replace(/z(f)oo/, function($0,$1) {return $0.replace($1, $1.toUpperCase());})
'foobazFoobar'
// Improve the RegEx so `(f)` will only get replaced when it begins with a dot or new line, etc.
I just want to highlight the two parameters of function makes finding a specific format and replacing a capturing group within the format possible.
SOLUTION
a.replace(/(f)/,(m,g)=>g.toUpperCase())
for replace all grup occurrences use /(f)/g regexp. The problem in your code: String.prototype.toUpperCase.apply("$1") and "$1".toUpperCase() gives "$1" (try in console by yourself) - so it not change anything and in fact you call twice a.replace( /(f)/, "$1") (which also change nothing).
let a= "foobar";
let b= a.replace(/(f)/,(m,g)=>g.toUpperCase());
let c= a.replace(/(o)/g,(m,g)=>g.toUpperCase());
console.log("/(f)/ ", b);
console.log("/(o)/g", c);
Given a dictionary (object, in this case, a Map) of property, values, and using .bind() as described at answers
const regex = /([A-z0-9]+)/;
const dictionary = new Map([["hello", 123]]);
let str = "hello";
str = str.replace(regex, dictionary.get.bind(dictionary));
console.log(str);
Using a JavaScript plain object and with a function defined to get return matched property value of the object, or original string if no match is found
const regex = /([A-z0-9]+)/;
const dictionary = {
"hello": 123,
[Symbol("dictionary")](prop) {
return this[prop] || prop
}
};
let str = "hello";
str = str.replace(regex, dictionary[Object.getOwnPropertySymbols(dictionary)[0]].bind(dictionary));
console.log(str);
In the case of string conversion from CamelCase to bash_case (ie: for filenames), use a callback with ternary operator.
The captured group selected with a regexp () in the first (left) replace arg is sent to the second (right) arg that is a callback function.
x and y give the captured string (don't know why 2 times!) and index (the third one) gives the index of the beginning of the captured group in the reference string.
Therefor a ternary operator can be used not to place _ at first occurence.
let str = 'MyStringName';
str = str.replace(/([^a-z0-9])/g, (x,y,index) => {
return index != 0 ? '_' + x.toLowerCase() : x.toLowerCase();
});
console.log(str);

Unable to capitalize the word in JS

I am trying to change the entire word into capital letters. What is wrong with my approach, for individual letters toUpperCase is working fine
var name = "gates";
for (var i=0; i< name.length; i++){
name[i] = name[i].toUpperCase();
}
name;
So the thing is "hello world".toUpperCase() is working fine as expected. Why the looping individual characters in array does not work as expected!.
Is this some property in arrays/strings especially in JS?
As RGraham mentioned the string letters cannot be modified, I don't understand the negative feedback of the community. Even the question seems to be valid.
The reason this doesn't work, is that accessing a string using the array syntax is read-only. As per the MDN docs:
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. (See
Object.defineProperty() for more information.)
So, console.log(name[0]) will work, but name[0] = "G"; will not update the name variable.
You don't need to loop through the letters, just do:
var name = "gates";
name = name.toUpperCase();
A string is immutable in most languages, meaning, you can't change individual characters, or add something, without ending up with a new one.
name = name.toUpperCase();
Will give you what you need, but a new, all-caps string is put in the variable 'name'.
Accoring to http://www.w3schools.com/jsref/jsref_touppercase.asp
var str = "Hello World!";
var res = str.toUpperCase();
http://www.w3schools.com/jsref/jsref_touppercase.asp
var str = "Hello World!";
var res = str.toUpperCase();
Result:
HELLO WORLD!

Categories