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!
Related
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);
I have a basic replace function, but I need it to perform a global replace, as it seems to be stopping on the first instance. I do not want to do it with a Regex. Applying the global attribute seems easy enough in most examples, but I am passing in a variable as the value to be replaced, and /g is having no impact. What am I doing wrong? Here is the example without the /g:
test string
"Why is my ^%friend so ^%? Maybe I need a ^!% one, abrand^!% one"
Simple replace function
function translate(oddStr) {
var tagDictionary = {};
tagDictionary['^%'] = 'odd';
tagDictionary['^!%'] = 'new';
Object.keys(tagDictionary).forEach( function (tag) {
oddStr = oddStr.replace(tag, tagDictionary[tag]);
});
return oddStr;
};
This function returns the first instance of each replaced, as expected. How can I apply /g to the tag variable in the forEach?
Use a split-join combo like this:
oddStr = oddStr.split(tag).join(tagDictionary[tag]);
"Why is my ^% friend so ^%? Maybe I need a ^!% one, abrand ^!% one".replace(/\^%/g, 'odd').replace(/\^!%/g, 'new')
"Why is my odd friend so odd? Maybe I need a new one, abrand new one"
If you need to create the regular expression from string, you can use RegExp constructor: new RegExp('\\^%', 'g').
If you don't have control over the tag-dictionary and it is coming from some external resource, then you will have to properly escape the tags.
Instead of using adhoc symbols for templating you should ideally use something like lodash.template
You need to escape your regex special characters (^=Start of string)
function translate(oddStr) {
var tagDictionary = {
'\\^%' : "odd",
'\\^!%' : 'new'
};
Object.keys(tagDictionary).forEach( function (tag) {
var r = new RegExp(tag, "g");
oddStr = oddStr.replace(r, tagDictionary[tag]);
});
return oddStr;
};
console.log(translate("Why is my ^%friend so ^%? Maybe I need a ^!% one, a brand ^!% one"));
I have a simple array loop, runs perfect in jsFiddle showing all items, see https://jsfiddle.net/8odoros/b27ocs4d/1/
What's strange is that putting the same script here as a snippet runs by letter, showing the first string letter by letter. I feel stupid, am I missing something? Check it out:
var name = ['Helen','Jim','Thomas','Luke','Theodore'];
var div = document.getElementById('cards');
for(var i=0;i<5;i++){
var newHtml = name[i]+' '+i+'</br>';
div.innerHTML = div.innerHTML + newHtml;
}
<div id="cards"></div>
Word name is a reserved word (as #prasad answered) in javascript that why your code was not working as expected.
See below code, after changing name with names. Its seems working as was working in jsfiddle.
var names = ['Helen','Jim','Thomas','Luke','Theodore'];
var div = document.getElementById('cards');
for(var i=0;i<5;i++){
var newHtml = names[i]+' '+i+'</br>';
div.innerHTML = div.innerHTML + newHtml;
}
<div id="cards"></div>
Note: name can only be used as local variable inside a function or iife and can not used as global varibale.
Try any one of the function its working. name is reserved word of javascript.But applied with in function .Its not act as a reserved word.This is one of the way preventing the action.
(function () {
var name = ["Helen","Jim","Thomas","Luke","Theodore"];
var div = document.getElementById('cards');
for(var i=0;i<5;i++){
var newHtml = name[i]+' '+i+'</br>';
div.innerHTML = div.innerHTML + newHtml;
}
})()
<div id="cards"></div>
Apparently name is a property of window and it has a setter which converts the input value to a string. Your code is trying to assign an array to that property which is magically converted to a string:
var name = ["foo", "bar"];
console.log(name); // array converted to "foo,bar"
So why does it work on jsFiddle? The answer is that, by default, jsFiddle wraps your code inside a function, something like this:
<script>
window.onload = function() {
var name = ["foo", "bar"];
console.log(name); // ["foo", "bar"]
}
</script>
This creates a closure where var name creates a new variable instead of referring to window.name. If you change your jsFiddle settings (JavaScript tab > Load type > No wrap - in body) then you get the same result as the StackSnippet like this:
<script>
var name = ["foo", "bar"];
console.log(name); // "foo,bar"
</script>
The solution is not to pollute the global namespace in the first place. That way you do not have to lookup the list of "words not to use as JavaScript variables".
name AKA window.name
Well name is most definitely not a reserved word in javascript.
name AKA window.name is the name of the window. Its value is set by a setter function and as the window name should be a string. So when you set it with name=["foo","bar"] it is converted to a string.
It is unfortunate that Javascript must share the global name space with every man and his dog and this illustrates another reason to avoid the global scope whenever possible.
This question is about
why the outputs are different
not how can i achieve the proper output.
I am unable to understand why the output of following two scenarios is not the same, even if I am giving the same argument to the JSON.parse() function.
FIRST scenario
obj = {a:"asdf"};
var newObj = JSON.parse(JSON.stringify(obj)); //newObj = {a:"asdf"}
Debugging
SECOND scenario
var newObj = JSON.parse("{"a":"asdf"}"); //this gives an error
The problem is with quotes.
var newObj = JSON.parse('{"a":"asdf"}');
should work correctly.
In Javascript, we use quotes (single or double) to represent a String. When you want to define a String that contains quotes, then you must use different quotes, or escape the quotes using backslash \ character.
var newObj = JSON.parse("{\"a\":\"asdf\"}");
also works fine.
You might think that
var newObj = JSON.parse("{'a':'asdf'}");
would work, but no. In JSON, strings are defined using Double quotes only.
why the outputs are different
Because the inputs are different.
FIRST scenario
obj = {a:"asdf"};
var newObj = JSON.parse(JSON.stringify(obj));
Here the input parameter of JSON.parse is JSON.stringify(obj)and this is a string that reads {"a":"asdf"}.
SECOND scenario
var newObj = JSON.parse("{"a":"asdf"}");
Here the input parameter of JSON.parse is a string that reads { and the rest is broken code.
Confusion arises because the console debugger decides all strings should be shown on the console encapsulated with a ", but this is just a way for the console to tell you that this value is of type String. It does not check whether you have " inside and escape them.
The encapsulating " are not part of the string, only a way of telling it is a string.
If console.logging JSON.stringify(obj) gets you "{"a":"asdf"}" try doing alert instead, or document.write. These will not add extra " and you will see that the value of JSON.stringify(obj) is actually {"a":"asdf"}, not "{"a":"asdf"}".
<html><head></head><body>
<script>
function JSONparse(string) {
document.write(string);
alert(string);
console.log(string);
return JSON.parse(string);
}
var obj = {a:"asdf"};
result = JSONparse(JSON.stringify(obj));
</script>
</body></html>
var newObj = JSON.parse('{"a":"asdf"}');
a="12345"
a[2]=3
a[2]='9'
console.log(a) //=> "12345"
What is going on?? This quirk caused me 1 hour painful debugging. How to avoid this in a sensible way?
You cannot use brackets to rewrite individual characters of the string; only 'getter' (i.e. read) access is available. Quoting the doc (MDN):
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.
That's for "what's going on" part of the question. And for "how to replace" part there's a useful snippet (taken from an answer written long, long ago):
String.prototype.replaceAt = function(index, char) {
return this.slice(0, index) + char + this.slice(index+char.length);
}
You may use as it is (biting the bullet of extending the JS native object) - or inject this code as a method in some utility object (obviously it should be rewritten a bit, taking the source string as its first param and working with it instead of this).
According to this question, this is not supported among all browsers.
If your strings aren't too long, you can do this relatively easy like that:
var a="12345";
a = a.split("");
a[2]='9';
a = a.join("");
console.log(a);
var letters = a.split('');
letters[2] = 3;
letters[2] = 9;
console.log(letters.join(''));
http://jsfiddle.net/XWwKz/
Cheers