I am trying to learn js basics.
I tried analysing the string count code but I am not sure about certain statements.
can you guys tell me why it's behaving in such a way?
this will help to understand better and in future, I can fix the issues by myself.
providing code below
String.prototype.count=function(c) {
var result = 0;
var i = 0;
console.log("this--->" + this); // how come this prints strings here, since we dont pass stings here
console.log("this.length--->" + this.length);
for(i;i<this.length;i++)
{
console.log("this[i]--->" + this[i]); // here we did not declare this an array anywhere right then how come its taking this[i] as s and stings also we did not put in any array
console.log("c--->" + c);
if(this[i]==c)
{
result++;
console.log("inside if result++ ---->" + result++);
// here it prints 1 and 3 but only two times s is present so it should print 1 and 2 right
}
}
console.log("out of for loop result--->" + result);
// how its printing 4 but s is present only two times
return result;
//console.log("out of for loop result--->" + result);
};
console.log("strings".count("s")); //2
output
this--->strings
this.length--->7
this[i]--->s
c--->s
inside if result++ ---->1
this[i]--->t
c--->s
this[i]--->r
c--->s
this[i]--->i
c--->s
this[i]--->n
c--->s
this[i]--->g
c--->s
this[i]--->s
c--->s
inside if result++ ---->3
out of for loop result--->4
4
Questions from your code example are basicly about 2 issues:
this - is JS keyword. You don't have to initialize it, it automatically defined everytime, everywhere in your JS code. And it could mean different things in different situations, but it's too advanced topic if you've just started learning JS. For now lets just say, that this refers to the context, that called count() function, which is the string "strings". So it has length and you can iterate over it as an array of characters
Why the count rose to number 4, when it should be 2? Because when you found a match between current letter of the string and the character "s" (line with this[i]==c) you increment the result by 1 using result++. But you do it also in your console.log right after it, so it gets increased by 2 every time it finds a match
console.log("this--->" + this); // how come this prints strings here, since we dont pass stings here
That prints a string because you have a string + something. This is called string concatenation and the result of string concatenation is a string. In this case, this is the object that called the count function which was a string.
console.log("this[i]--->" + this[i]); // here we did not declare this an array anywhere right then how come its taking this[i] as s and stings also we did not put in any array
this is a string. Bracket notation on a string will return the char at the provided index.
result++;
console.log("inside if result++ ---->" + result++);
// here it prints 1 and 3 but only two times s is present so it should print 1 and 2 right
the result++ notation is the same as result += 1, but result++ does the addition of 1 AFTER the value is evaluated while ++result will do it before. So in this example the order of events is:
add 1 to the result, then print the console.log, then add 1 to the result
Hope that helps!
Related
I have the following problem:
I was trying, inside a common HTML page mixed with some Javascript, to write a simple program so that a specific div would be filled with the result of a function.
The result of the function consists of a string of text, below a row of dashes with as many dashes as the number of characters inside the text string.
My code is as follows, inside the body:
<div id="div1"></div>
<script>
let tab = "";
function result(text) {
for (i in text) {
tab += '-';
}
return "<p>" + tab + "<br>" + text + "</p>";
}
document.getElementById("div1").innerHTML = result("Bear") + result("Bear") + result("Bear");
</script>
The rendered HTML returns the following result:
Only the first invocation of the function works as expected: 4 dashes for 4 letters. But the second invocation renders twice as many dashes, and the third one three times as many.
Perhaps "return" is not the command to use?
You only set tab to an empty string at the start of the program.
You don't set it to an empty string inside the function.
So it never gets reset to an empty string.
Every time you call the function, tab just gets dashes added to whatever is there.
If you want to reset it every time the function is called, then reset it inside the function.
It waa already answered. Still a different view could help:
Issue &. Fix
Each call of result(text) is adding dashes to the global variable tab (here 3 times the same length: 4 + 4 + 4).
Usually let keyword is described with following:
declare a scoped variable, which is only valid and has a lifetime within the current [scope] (here: for the whole script, not only inside the function).
Commented and properly formatted (proper indentation eases readability!) your script:
let tab = ""; // declared at start of the script, means global scope
function result(text) {
// move declaration here so it always is reborn (local scope = new lifetime)
for (i in text) {
tab += '-';
}
return "<p>" + tab + "<br>" + text + "</p>";
}
From your described intend scoped should rather be declared inside the function. So it has local scope (known inside the function only).
Moreover it will automatically be reset at each call of the function.
Alternative
In old console usage (Text-UI) and still in ASCII-Art the basic method to draw a textual line with any character like dashes - was described either of:
fill width of n characters with character a
return string which contains character a repeated for n times
So they invented functions like fillString( a, n ) or a.repeat( n ).
Similar can be done in JavaScript.
Benefits:
you can parameterize the filler character, e.g to = or _
you can easily reuse this generic function
Bonus: Review
My experience taught me to pay attention to naming in code.
Express intend and purpose, so you and everybody else can see now – and in 6 months – the mraning of variables and functions at a glance.
most functions return a result, this does more: function addSameWidthLineAbove(text)
let line or textualBorder or dashes
This is an extremely beginner question, but i have a value that i want to transform multiple times, each time taking the output from the previous result as input.
Lets say i want to iterate through an array of characters [a,6,b,4] and append each of them the word brownbear. The final output that i would want is brownbeara6b4. Also, I'm not looking for a solution that just dumps the context of the array and concatenates it to the word. I need something that can iteratively transform data, no matter what the use case is.
To maybe provide another example, i want to run a function x amount of times on some value. Each time I want to take the output of the function and use it as input for the next time the function is ran.
How would i solve this using JS?
Maybe you are looking for a recursive function that runs X times. In that case, this can be helpful.
Basically what I'm doing here is to call the same function with the transformed data of each iteration over and over until i reach X amount of times.
var my_array = ["a", "1", "b", "2"]
var times = 2
function iterative_function(data, times_to_be_run = 1){
if(times_to_be_run > 0){
var transformed_data = data.map(a=> a + " hello")
return iterative_function(transformed_data, times_to_be_run - 1)
}else{
return data
}
}
console.log(
iterative_function(my_array, times)
)
Here is my code:
for (let i = 0; i <= 100; i++) {
let output = "";
if (i % 3 === 0) {
output += "Cool";
}
if (i % 5 === 0) {
output += "Breeze";
}
console.log(output || i);
}
In this code, I use a for loop to vary the value of the binding i from 0 to 100.
In the first if statement, I use the modulo and the addition assignment operator to add the string "Cool" to the binding output.
In the second if statement, I use the modulo and the addition assignment operator to add the string "Breeze" to the binding output.
The function of my last statement in the body of my for loop is to print the value of the output binding in the browser console. I do this through short-circuiting. Now, I understand the logic of short-circuiting with the "OR" operator, since the interpreter will short-circuit its full logic of comparing both operands and automatically choose the operand on the left if it can be converted to true, which strings and numbers can, so the operand output is always going to be chosen.
What I don't understand is why short-circuiting is needed to visibly print every value in the console. If I were to use the statement console.log(output); it consolidates the number type values, stating how many were printed in a row before it had to print a string.
Can someone please explain this logic? Why is short-circuiting needed here to prevent the consolidation?
If I were to use the statement console.log(output); it consolidates the number type values, stating how many were printed in a row before it had to print a string.
In case it isn't clear to others, what you're referring to is this:
This is an artifact of the browser console, which consolidates duplicate logs together, to make debugging easier. Here, it's consolidating the duplicate logged empty strings. It's not a issue with your code's logic. If you were to log the output by any other method, the blank outputs would be displayed serially, as you'd expect, rather than being clumped together:
const table = document.querySelector('table').children[0];
for (let i = 0; i <= 100; i++) {
let output = "";
if (i % 3 === 0) {
output += "Cool";
}
if (i % 5 === 0) {
output += "Breeze";
}
table.innerHTML += `<tr>Cell value: ${output}</tr>`;
}
<table>
<tbody>
</tbody>
</table>
Your code is perfectly fine, you just need to find a way to display it other than console.log so that its unintuitive clumping doesn't mess things up.
You can also turn off the grouping by unchecking "Group Similar":
Apparently JS implementation in IE9 contains (IMO, critical) bug in handling array literals.
In IE9 in some cases this code:
var a = [1,2,3,4,];
will create array of length 5 with last element equals to undefined.
Here are two versions of my KiTE engine test pages:
http://terrainformatica.com/kite/test-kite.htm - works in IE9
http://terrainformatica.com/kite/test-kite-ie9-bug.htm - fails in IE9
The only difference is that first document contains data.contacts property initialized as [1,2,3,4] and second one as [1,2,3,4,].
Internal IE debugger reports that data.contacts array contains 5 elements in second case. Without debugger this code fails at line 98 in kite.js (trying to get property of undefined - fifth element of that data.content array )
Questions:
How and where people usually report bugs in IE?
Have you seen anything similar to this problem? I am looking for simplest case where this problem is reproducible.
Update: here is the test http://jsfiddle.net/hmAms/ where all browsers (IE9 included) agree on the fact that var a = [1,2,3,4,]; is of length 4.
A single trailing comma in an array literal should be ignored. Two trailing commas is an elision and should add one to the array's length. So:
alert( [1,2,3,4,].length ); // 4
alert( [1,2,3,4,,].length ); // 5
Some versions of IE (< 9?) treat the single trainling comma as an elison and incorrectly add one to length, so the results above are 5 and 6 respsectively. That is inconsistent with ECMA-262 §11.1.3 and therefore is a bug.
The purpose of an elision is to increase array length without creating a extra property or assigning directly to length, so:
var x = [,1,,];
is equivalent to:
var x = new Array(3);
x[1] = 1;
The result in both cases should be an array with length 3 and one property named '1' with value 1. The leading comma and trailing comma pair are elisions, they only affect the length, they do not create properties. IE interprets the leading comma correctly but incorrectly interprets both trailing commas as elisions, incrementing the length by 1 too many.
var x = [,1,,3,,];
var s = 'length: ' + x.length;
for (var p in x) {
s += '\nindex ' + p + ' has value ' + x[p];
}
alert(s);
The result should be:
length: 5
index 1 has value 1
index 3 has value 3
Incidentally, this bug has probably been around since IE allowed array literals, version 4 at least (1997?).
That's not a bug. That's exactly how it should behave. Microsoft did that on purpose. If you want an array with only 4 items, get rid of the last comma. Simple as that.
If the results you're after is to have an extra, undefined value at the end, you're in luck. Even without the comma, it'll be undefined. It, and every single number after 3.
I am sorry for the very newbie question, but this is driving me mad.
I have a word. For each letter of the word, the characters position in one array is found and then returns the character at the same position found in a parallel array (basic cipher). This is what I already have:
*array 1 is the array to search through*
*array 2 is the array to match the index positions*
var character
var position
var newWord
for(var position=0; position < array1.length; position = position +1)
{
character = array1.charAt(count); *finds each characters positions*
position= array1.indexOf(character); *index position of each character from the 1st array*
newWord = array2[position]; *returns matching characters from 2nd array*
}
document.write(othertext + newWord); *returns new string*
The problem I have is that at the moment the function only writes out the last letter of the new word. I do want to add more text to the document.write, but if I place within the for loop it will write out the new word but also the other text inbetween each word. What i actually want to do is return the othertext + newWord rather than document.write so that I can use it later on. (just using doc.write to text my code) :-)
I know its something really simple, but I cant see where I am going wrong. Any advice?
Thanks
Issy
The solution is to build newWord within the loop using += instead of =. Just set it to an empty string before the loop.
There are other problems with this code. Variable count is never initialized. But let's assume that loops should be using count instead of position as it's principal counter. In that case, if I am not mistaken, this loop will just generate array2 as newWord. First two lines of loop's body cancel each other in a matter of speaking, and position will always be equal to count, so letters from array2 will be used sequentially from beginning to the end.
Could you provide one example of input and desired output, so that we understand what you actually want to accomplish?
A good way of structuring your code and your question is that you define a function that you need to implement. In your case this could look like:
function transcode(sourceAlphabet, destinationAlphabet, s) {
var newWord = "";
// TODO: write some code
return newWord;
}
That way, you clearly state what you want and which parameters are involved. It is also easy to write automatic tests later, for example:
function testTranscode(sourceAlphabet, destinationAlphabet, s, expected) {
var actual = transcode(sourceAlphabet, destinationAlphabet, s);
if (actual !== expected) {
document.writeln('<p class="error">FAIL: expected "' + expected + '", got "' + actual + '".</p>');
} else {
document.writeln('<p class="ok">OK: "' + actual + '".');
}
}
function test() {
testTranscode('abcdefgh', 'defghabc', 'ace', 'dfh');
}
test();