Why is the passed in value undefined when accessing the map method? - javascript

When I run the snippet below in JSbin it says that capitalize won't work because the property is undefined. I looked at the documentation and it mentioned the use of the word 'this' but I am not quite sure if that applies here since the string value passed in is correct (console logged it to confirm). Why is the capitalize method not apple to work off the map value?
class bookTitle {
constructor(title) {
this.title = title; // this creates the object ONCE, see top of jasmine file for explanation
}
get title() {
return this._title; // retrieves the title string
}
set title(title) {
this._title = this.titleCreator(title); // calls the method and sets title, see top of jasmine file for explanation
}
titleCreator(string) {
if (string == null){
return string; // catches first error
}
// Note that this isn't meant to be a fully fledged title creator, just designed to pass these specific tests
var littleWords = ['and', 'do', 'the', 'a', 'an', 'in', 'of']; // These are the words that we don't want to capitalize
var modifiedString = string
.split(' ') // Splits string into array of words, basically breaks up the sentence
.map(function(word,index) {
if (index == 0) {
return this.capitalize(word); // capitalize the first word of the string
} else if (littleWords.indexOf(word) == -1) {
return this.capitalize(word); // capitalize any words that are not little, the -1 is returned by indexOf if it can't find the word in the array
} else if (littleWords.indexOf(word) >= 0) {
return word; // do not capitalize as this word is in the list of littleWords
}
})
.join(' '); // Joins every element of an array into a string with a space inbetween each value. Basically you created a sentence from an array of words
return modifiedString;
}
capitalize(word) {
return word.charAt(0).toUpperCase() + word.slice(1);
// This function just capitalizes the word given to it
}
}
let bookTitles = new bookTitle();
bookTitles.title = 'inferno';
console.log(bookTitles.title); // The goal is to output Inferno

The problem is that this within your map refers to the function you're passing to map. Use an arrow function (word, index) => { ... } instead and this should fall through to the parent class.
var modifiedString = string
.split(' ') // Splits string into array of words, basically breaks up the sentence
.map((word,index) => { // <-- ARROW FUNCTION
if (index == 0) {
return this.capitalize(word); // capitalize the first word of the string
} else if (littleWords.indexOf(word) == -1) {
return this.capitalize(word); // capitalize any words that are not little, the -1 is returned by indexOf if it can't find the word in the array
} else if (littleWords.indexOf(word) >= 0) {
return word; // do not capitalize as this word is in the list of littleWords
}
})
.join(' ');

Related

How to convert string to camelCase without using RegEX

I'm trying to do a challenge which is converting all strings into camelCase but without using regex, only using the methods like(split, slice, replace, includes.. etc). Some words have spaces and should remove them. Here's the CODE and I'm really STUCK. NOTE: the user enters the STRING and when user clicks the button should return to the camelCase.
INPUT =>
//underscore_case
//first_name
//Some_Variable
// calculate_AGE
//delayed_departure
OUTPUT =>
//underscoreCase
//firstName
//someVariable
//calculateAge
//delayedDeparture
document.body.append(document.createElement('textarea'));
document.body.append(document.createElement('button'));
document.querySelector('button').addEventListener('click', function() {
const text = document.querySelector('textarea').value;
const row = text.split('\n');
let [...n] = '';
for (const theText of row) {
const lowerText = theText.toLowerCase().trim();
if (lowerText.includes('_')) {
n = lowerText.replace('_', ' ');
console.log([...n]);
}
}
});
Explanation of this simple algorithm:
Your input must have words that split by a certain character, as you need something to identify which part of the string is a word. Let's assume your string has words separated by '//' instead of spaces as you mentioned in the comments, and each of those words is split by '_'.
First you need to split all words in the string into an array, you can use the split() method in order to do that.
Then when iterating through each word, split it again with split() but this time with whatever identifies the different words, in our case it's _.
Iterate through each split words, if it's the first word lowercase it using toLowerCase() and add it to the new word variable, if not, lowercase it and capitalize the first letter.
And that's it. Here's the implementation:
const inputWithoutCamelCase = 'hello_world // HOW_ARE_YOU // foo_BAR'
function stringToCamelCase(string) {
const allNames = string.split('//')
let camelCasedString = '';
for (const name of allNames) {
camelCasedString += nameToCamelCaseHelper(name);
}
return camelCasedString;
}
function nameToCamelCaseHelper(word) {
const splittedName = word.split('_');
let camelCasedName = '';
for (let i = 0; i < splittedName.length; i++) {
if (i === 0) {
camelCasedName += splittedName[i].toLowerCase();
} else {
camelCasedName += capitalizeFirstLetter(splittedName[i].toLowerCase())
}
}
return camelCasedName;
}
function capitalizeFirstLetter(string) {
return string.charAt(0).toUpperCase() + string.slice(1);
}
stringToCamelCase(inputWithoutCamelCase) // helloWorld howAreYou fooBar

How do I structure this new logic to fit into pre-existing code?

I have written a code that removes all consonants before a vowel from a string and replaces it with an 'r' and in the case, the string starts with a vowel it should return the word without doing anything to it. Now, I want to add two things I came up with to it but unfortunately, I have not been able to:
1. When the string input is all consonants then it should do nothing and just return the string.
2. If user types in space like so ' ' then it should be trimmed.
How do I place this logic in the code below without affecting what is already working?
const scoobyDoo = str => {
if(typeof str !== 'string'){
return 'This function accepts strings only';
}
let newStr = str.toLowerCase().split('');
let arrWord = newStr.length;
let regex = /[aeiou]/gi;
if (newStr[0].match(regex)){
let nothing = newStr.join('');
return nothing;
}
else {
for (let i = 0; i < arrWord; i++){
let vowelIndex = newStr.indexOf(str.match(regex)[i].toLowerCase());
newStr.splice(0, vowelIndex, 'r');
return newStr.join('');
}
}
}
console.log(scoobyDoo('scooby'));//works as expected returns 'rooby'
console.log(scoobyDoo('ethane'));//works as expected returns 'ethane'
console.log(scoobyDoo('why'));// should return 'why'
console.log(scoobyDoo(' '));// should return trimmed space and a
text telling the user only spaces were entered.
I realise this doesn't really answer your question, but your existing logic is very complicated and you could achieve the same result with String.trim, .toLowerCase and .replace:
console.log('scooby'.trim().toLowerCase().replace(/^(?=.*?[aeiou])[^aeiou]+/, 'r'))
rooby
console.log('ethane'.trim().toLowerCase().replace(/^(?=.*?[aeiou])[^aeiou]+/, 'r'))
ethane
console.log('why'.trim().toLowerCase().replace(/^(?=.*?[aeiou])[^aeiou]+/, 'r'))
why
console.log('*' + ' '.trim().toLowerCase().replace(/^(?=.*?[aeiou])[^aeiou]+/, 'r') + '*')
**
The regexp uses a positive lookahead to ensure that there is a vowel in the string, and if so replaces all leading consonants with an r.
To do something more in line with your existing function, you could try this. It still makes extensive use of regex functions though.
const scoobyDoo = str => {
if(typeof str !== 'string'){
return 'This function accepts strings only';
}
// is it a blank string?
if (str.match(/^\s+$/)) {
return '';
}
// does it start with a vowel? if so, nothing to do
if (str.match(/^[aeiou]/i)) {
return str;
}
// does it only contain consonants?
if (!str.match(/[aeiou]/i)) {
return str;
}
// must not start with a vowel but still include one
return str.replace(/^[^aeiou]+/i, 'r');
}

What does [1] do on function?

I need an explanation on below js code,
function getURLParameter(url, name) {
return (RegExp(name + '=' + '(.+?)(&|$)')
.exec(url)||[,null])[1];
}
var id = getURLParameter(url, 'id');
console.log(id); //1
// let say the example of url is
// index.php?id=1&user=xxx
What is [1] on the return statement use for?
I am confuse on how does it get the value of 1 for the id
RegExp.prototype.exec() returns an array including the matches of the regular expression (or null).
[1] just accesses the second element in that array — in this case the value of the capturing group in the regular expression.
It's equivalent to:
function getURLParameter(url, name) {
var regexp = new RegExp(name + '=' + '(.+?)(&|$)');
var result = regexp.exec(url); // array containing the full string of
// characters matched, the value of the
// capturing group and the end anchor
// (or null)
if (Array.isArray(result)) {
return result[1];
} else {
return null;
}
}

Javascript: palindrome function?

I have working code for a simple word flipper:
var strFlip = function(str) {
return str.split(" ").map(function(word) {
return word.split("").reverse().join("");
}).join(" ");
};
console.log(strFlip("This is designed to swap the letter order of each word in the string"));
// "sihT si dengised ot paws eht rettel redro fo hcae drow ni eht gnirts"
I want to add an if/else to allow this code to now identify if each word in a string is a palindrome (spelled the same forward and backward ex: hannah).
So I tried continuing the .map() logic with:
var strFlip = function(str) {
return str.split(" ").map(function(word) {
return word.split("").reverse().join("");
}).join(" ").toLowerCase().map(function(test) {
if (test.split(" ") === word){
return true;
}else{
return false;
}
}
);
};
console.log(strFlip("Hannah loves her racecar"));
BUT.... unsurprisingly, it returns an error essentially stating that the long linked collection of functions before the if section is not itself a function:
TypeError: str.split(...).map(...).join(...).toLowerCase(...).map is not a function
I was also getting lost trying to match all of the curly braces, but I think I got them all.
So, is it possible to add the if/else within?
.join(" ").toLowerCase() returns a string, not an array. The error is stating that 'some string'.map is not a function because it's undefined.
If what you want is an array that indicates whether a word at an index is a palindrome then...
var sentence = 'Eve drives a racecar',
words = sentence.split(" ").map(function(word) {
var isPalindrome = word.length > 1 && (word.toLowerCase() === word.toLowerCase().split("").reverse().join(""));
return { text: word, isPalindrome: isPalindrome };
});
alert(JSON.stringify(words));

Why can't I simply update array[i] using an assignment statement in Javascript

My function is supposed to replace vowels in an inputted string with capitalized versions of themselves ("a" becomes "A", "dog" becomes "dOg")
It takes a string and creates an array to store and return the changed output
function LetterChanges(str) {
var array=[];
var n =str.length;
for (var i =0;i<n;i++){
if (/[a-z]/i.test(str[i])){
if (array[i]==="a" || array[i]==="e" || array[i]==="i" || array[i]==="o"|| array[i]==="u")
{
array[i]=array[i].toUpperCase();
};
}
return array;
}
Why does my array[i]=array[i].toUpperCase() not work to replace the lowercase value with it's uppercase value?
When I print my array, it still has the lowercase value, despite me assigning the newly capitalized value into that index?
What about using a RegExp inside the replace function? It is very very very easier!
You can then use a function to elaborate the string to replace and then return it to the replace function. In your case it will only return the uppercase value of the vowel.
Here's the code:
function LetterChanges(str) {
return str.replace(/[aeiou]/g, function(s) { return s.toUpperCase() });
}
Example:
LetterChanges("hello!");
> "hEllO!"
LetterChanges("aeiou");
> "AEIOU"
LetterChanges("dntrplc");
> "dntrplc"
In JavaScript, strings are immutable:
var s = "dog";
s[1] = 'O'; // Does nothing!
Thus, you must create a new string each time. You can create a method to do this like so:
String.prototype.replaceAt = function(index, character)
{
return this.substr(0, index) + character + this.substr(index+character.length);
};
Here's a working copy of your code that will utilize this function (I fixed a few of your issues):
String.prototype.replaceAt = function(index, character)
{
return this.substr(0, index) + character + this.substr(index+character.length);
};
function LetterChanges(str) {
for (var i =0;i<str.length;i++)
{
if (/[a-z]/i.test(str[i])) //Note: This test is pretty useless
{
if (str[i]==="a" || str[i]==="e" || str[i]==="i" || str[i]==="o"|| str[i]==="u")
{
str = str.replaceAt(i, str[i].toUpperCase());
}
}
}
return str;
}
document.write(LetterChanges("dog")); // Print dOg
I believe you need to initialize your array. That is, this
var array=[];
should be
var array=str.split('');
Your function is missing a closing bracket ('}').
Did you know you can use a function to replace matching text?
function uppercaseVowels(str){
return str.replace(/([aeiou])/g, function(a, b){
return b.toUpperCase();
});
}
var s='the quick red fox jumped over the lazy brown dog.';
uppercaseVowels(s)
/* returned value: (String)
thE qUIck rEd fOx jUmpEd OvEr thE lAzy brOwn dOg.
*/

Categories

Resources