9
function SimpleSymbols(str) { 
    var letter =['a','b','c','d','e','f','g','h','i','j',
    'k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'];

    var newstr = "";
    for (var i = 0; i<str.length; i++){
        if (str.charAt(i).toLowerCase() in letter){
            newstr += "M";
        }
        else{
            newstr += "X";
        }
    }

return newstr; 

}

If str is "Argument goes here" it returns XXXXXXXXX. WHy doesn't it return MMMMMMMMMM?

Dalorzo
  • 19,312
  • 7
  • 50
  • 97
Michael Sacks
  • 837
  • 1
  • 10
  • 17

3 Answers3

10

you do not look up an entry in an array with in. use indexOf() to find the position of an array entry. indexOf() will return the position or -1 if no entry is found.

for (var i = 0; i<str.length; i++){
    var strChar = str.charAt(i).toLowerCase();

    if ( letter.indexOf(strChar) >= 0 ) {
        newstr += "M";
    }
…
dreamlab
  • 3,315
  • 17
  • 23
4

The in operator returns true if the object has a property with that name, not with that value.

An array is basically an object with numeric properties. I.e. the indexes are the property names of the object. It basically looks like this:

var letters = {
  0: 'a',
  1: 'b',
  ...
  length: ...
};

So in your case the condition will only be true if str.charAt(i).toLowerCase() returns a number between 0 and letter.length (and since charAt only returns one character, it can only be 0-9).

Example:

> var letters = ['a', 'b', 'c'];
> 'a' in letters // array doesn't have a property 'a'
false
> 0 in letters   // array has a property 0 (it's the first element)
true

So since, "Argument goes here" doesn't contain any digits, the in condition will always be false and that's why you get XXXXXX... as result.

See the question "How do I check if an array includes an object in JavaScript?" for testing the existence of an element in an array.


FWIW, to make the in operator work, you would have to create an object of the form:

var letters = {
  'a': true,
  'b': true,
  // ...
};

but that's a bit cumbersome to write.

Community
  • 1
  • 1
Felix Kling
  • 705,106
  • 160
  • 1,004
  • 1,072
0

Allow me to offer a side view, another way handle what I think you intent to do by using Regular Expressions with something like:

"test2".replace(/[a-z]/gi,"M").replace(/[^M]/g,"X") //Outputs "MMMMX"

String.replace will replace an string that contains letters from [a-z] the i at the end of the expression means case insensitive. g means will search for all possible matches and not just the first match. In the second expression [^M] this ^ means negation so anything that is not an M will be replaced with X.

There is another way in which we implement a custom function within the String.replace using Regular Expressions and it can be implemented like this:

"test2".replace(/([a-z])|([^a-z])/gi,
     function(m,g1, g2){ 
            return g1 ? "M" : "X";  
     });

In regular expression parenthesis creates groups and | means or in this expression ([a-z])|([^a-z]) there 2 groups one with letters from a-z and the other which means everything that is not a-z with the replace function we asked only for group g1 if it is group 1 is M otherwise is an X.

Another cool thing you could do is add this function to all your string by prototyping it like:

String.prototype.traverse = function(){ return this.replace(/([a-z])|([^a-z])/gi,function(m,g1){ return g1 ? "M" : "X"  });}

Then it can be used as simple as: "test1".traverse();

Dalorzo
  • 19,312
  • 7
  • 50
  • 97