The snippet below is from MDN - A reintroduction to Javascript, it is supposed to demonstrate IIFE. I kinda see that it is supposed to count the characters in this text node but I am not sure about a couple things. The first is why does the for statement have 2 arguments in the first argument section var i=0, child. The second is more general, how does it work with this function calling itself .. can someone explain the overall flow to me please?
var charsInBody = (function counter(elm) {
if (elm.nodeType == 3) { // TEXT_NODE
return elm.nodeValue.length;
}
var count = 0;
for (var i = 0, child; child = elm.childNodes[i]; i++) {
count += counter(child);
}
return count;
})(document.body);
The first is why does the for statement have 2 arguments in the first argument section var i=0,child ?
A for loop is just a condensed version of a while loop, that means that:
for(declarations; condition; last) {
body
}
is the same as:
declarations
while(condition) {
body
last
}
That means that in your case it is as:
var i = 0, child;
while(child = elm.childNodes[i]) {
count += counter(child);
i++
}
So actually child just defines a new variable before the loop
Related
I'm trying to write a Javascript function that counts the vowels in a string by calling another function inside that function, but when I test it in the console it returns 0.
Here is my first function that works fine and recognizes if a string is a vowel:
function isVowel(ch){
var pattern = /[aeiouAEIOU]/
return pattern.test(ch);
};
For the second function none of my ideas have worked. Here are a few examples of what I have tried so far:
This one returns me a 0:
function countVowels(str){
var count = 0;
for(var i; i <= str.length; ++i){
if(isVowel(i)){
++count;
}
}
return count;
};
I also tried the above, but removing the .length after str in the for() area.
Another example, but this one gives me an error:
function countVowels(str){
var count = 0
var pattern = /[aeiouAEIOU]/
for(var i = 1; i <= str.length(pattern); ++i){
if(isVowel(i)){
++count;
}
}
return count;
};
I've tried various other functions as well, but for the sake of keeping this post relatively short I won't continue to post them. I'm quite new to Javascript and I'm not sure what I'm doing wrong. Any help would be greatly appreciated!
Try using .match() with the g attribute on your String.
g: global
i: case insensitive
Regexp documentation
function countVowels(ch){
return ch.match(/[aeiouy]/gi).length;
}
var str = "My string";
alert(countVowels(str)); // 2
Although Robiseb answer is the way to go, I want to let you know why you code is not working (I'm referring your first attempt). Basically you made two mistakes in the loop:
As CBroe stated, you are passing i to your isVowel function. i is a integer representing the index of the loop, not the actual character inside the string. To get the character you can do str.substr(i, 1), what means "give me one character from the position i inside the string".
You are not giving a initial value to the i variable. When you create a variable, it is undefined, so you can not increment it.
alert(countVowels("hello"));
function countVowels(str) {
var count = 0;
for (var i = 0; i <= str.length; ++i) {
if (isVowel(str.substr(i, 1))) {
count++;
}
}
return count;
};
function isVowel(ch) {
var pattern = /[aeiouAEIOU]/
return pattern.test(ch);
};
UPDATE: You will see that other answers use other methods to select the character inside the string from the index. You actually have a bunch of different options. Just for reference:
str.slice(i,i+1);
str.substring(i,i+1);
str.substr(i,1));
str.charAt(i);
str[i];
i is the index, not the character. It should be:
if (isVowel(str[i])) {
count++;
}
Also, str.length(pattern) is wrong. length is a property, not a function, so it should just be str.length.
You forgot to assign the value 0 to i variable
And parameter for isVowel is the character, not the index of string
Here information about the JS language: https://stackoverflow.com/tags/javascript/info
function isVowel(ch){
var pattern = /[aeiouAEIOU]/
return pattern.test(ch);
}
function countVowels(str){
var count = 0;
// you forgot to assign the value to i variable
for(var i = 0; i < str.length; i++){
// isVowel(str[i]), not isVowel(i)
if(isVowel(str[i])){
count++;
}
}
return count;
}
console.log(countVowels('forgot'))
Obviously you should do it this way:
function isVowel(c){
var lc = c.toLowerCase();
if(lc === 'y'){
return (Math.floor(Math.random() * 2) == 0);
}
return ['a','e','i','o','u'].indexOf(lc) > -1;
}
function countVowels(s){
var i = 0;
s.split('').each(function(c){
if(isVowel(c)){
i++;
}
});
return i;
}
console.log(countVowels("the quick brown fox jumps over the lazy dog"));
Which, although less efficient and less useful than other answers, at least has the entertaining property of returning a different count 50% of the time, because sometimes Y.
I'm trying to implement Heap's algorithm to find different permutations of a string and found a strange behaviour with a for loop, here's the code
function permAlone(str) {
var strArr = str.split(''),
permutations = [];
function swap(strArr, x, y) {
var tmp = strArr[x];
strArr[x] = strArr[y];
strArr[y] = tmp;
}
function generate(n) {
if (n === 1) {
permutations.push(strArr.join());
} else {
for (var i = 0; i != n; i++) {
generate(n - 1);
swap(n % 2 ? 0 : i, n - 1);
}
}
}
generate(strArr.length);
return permutations;
}
console.log(permAlone('aab'));
In the for loop within the generate function, if I put i = 0 the output of the script is ['a,a,b', 'a,a,b'] but if I put var i = 0 the output is ['a,a,b', 'a,a,b', 'a,a,b', 'a,a,b', 'a,a,b', 'a,a,b'].
I understand that var i would create a local variable for the loop, but don't understand in this case why it would change how the loop functions as there is no i variable declared anywhere else in the script.
Thanks any help appreciated.
The reason the behaviour changes if you have a global i variable is that you have multiple recursive calls to generate() all trying to control their own partially complete for loops with the same variable, and all setting i back to 0 when they start.
Picture what happens on the second iteration of the for loop: i is 1 because it has just been incremented, but then immediately a recursive call to generate() starts its own loop and sets i back to 0 again.
If you create a local variable with var then each for loop in each recursive call is independent of all the others.
Try stepping through the code with the debugger, or try adding the following as the first line inside the for loop and watch what happens to the variables when the code runs:
console.log('n:' + n + '; i: '+i);
I'm very new at recursion, and have been tasked with writing getElementsByClassName in JavaScript without libraries or the DOM API.
There are two matching classes, one of which is in the body tag itself, the other is in a p tag.
The code I wrote isn't working, and there must be a better way to do this. Your insight would be greatly appreciated.
var elemByClass = function(className) {
var result = [];
var nodes = document.body; //<body> is a node w/className, it needs to check itself.
var childNodes = document.body.childNodes; //then there's a <p> w/className
var goFetchClass = function(nodes) {
for (var i = 0; i <= nodes; i++) { // check the parent
if (nodes.classList == className) {
result.push(i);
console.log(result);
}
for (var j = 0; j <= childNodes; j++) { // check the children
if (childNodes.classList == className) {
result.push(j);
console.log(result);
}
goFetchClass(nodes); // recursion for childNodes
}
goFetchClass(nodes); // recursion for nodes (body)
}
return result;
};
};
There are some errors, mostly logical, in your code, here's what it should have looked like
var elemByClass = function(className) {
var result = [];
var pattern = new RegExp("(^|\\s)" + className + "(\\s|$)");
(function goFetchClass(nodes) {
for (var i = 0; i < nodes.length; i++) {
if ( pattern.test(nodes[i].className) ) {
result.push(nodes[i]);
}
goFetchClass(nodes[i].children);
}
})([document.body]);
return result;
};
Note the use of a regex instead of classList, as it makes no sense to use classList which is IE10+ to polyfill getElementsByClassName
Firstly, you'd start with the body, and check it's className property.
Then you'd get the children, not the childNodes as the latter includes text-nodes and comments, which can't have classes.
To recursively call the function, you'd pass the children in, and do the same with them, check for a class, get the children of the children, and call the function again, until there are no more children.
Here are some reasons:
goFetchClass needs an initial call after you've defined it - for example, you need a return goFetchClass(nodes) statement at the end of elemByClass function
the line for (var i = 0; i <= nodes; i++) { will not enter the for loop - did you mean i <= nodes.length ?
nodes.classList will return an array of classNames, so a direct equality such as nodes.classList == className will not work. A contains method is better.
Lastly, you may want to reconsider having 2 for loops for the parent and children. Why not have 1 for loop and then call goFetchClass on the children? such as, goFetchClass(nodes[i])?
Hope this helps.
I am learning javascript and came across a topic which mentions that the variables declared inside a function is available anywhere inside the function and javascript puts the variable definition at the top like in the below example:
var functionScope=function(){
for (var i=0; i< 10; i++){//code inside this loop}
return i;
}
console.log(functionScope()); //prints 10
The javascript actually turns the above function to the below:
var functionScope=function(){
var i;
for ( i=0; i< 10; i++){//code inside the for loop}
return i;
}
console.log(functionScope()); //prints 10
Since javascript is interpreted language, it executes line by line. How will it know that it should pull the variable to the top of the function after it has tried accessing the variable. When it tries to access the variable it should tell as undefined right?
Also if I go by the theory that the variables will be placed at the top of the function and can be accessed anywhere then the below code should print 10, but why the below code prints undefined?
var functionScope=function(){
console.log('The value os i is '+i);
var i = 20;
}
console.log(functionScope());
Could someone explain where my understanding is wrong?
One more doubt: Typically in Java, if I had to print the value of i outside the for loop, i would get an error, but in javascript does the variable still accessible outside outside the for loop as in case of fist example where the variable is defined inline inside the for loop. Am i missing something here?
var functionScope=function(){
for (var i=0; i< 10; i++);
return i
}
console.log(functionScope()); //prints 10
This is only a bad indentation. Because of the ; at the end of for, it doesn't includes the return i statement into the loop.
There is the well indented one to help you understand what really happens:
var functionScope=function() {
for (var i=0; i< 10; i++)
/* do nothing */;
return i
}
With var, you tell the JS that the variable is not global, and it'll be aviable only inside the function.
With =, you can set the variable's value.
var i; for (i = 0; ... and for (var i = 0; ... is the same.
In the third example, you don't have i inside the function. In this case, the JS'll try to find it as a global variable, outside the function. If you've set window.i = 1, it'll print The value os i is 1, otherwise it'll generate an error, because i is not defined nowhere.
var i = 0;
var fn = function() {
i = 1; //window.i = 1;
};
console.log(i); //prints 1
var i = 0;
var fn = function() {
var i = 1; //fn.i = 1;
}
console.log(i); //prints 0
var fn = function() {
var i = 1; //fn.i = 1;
}
console.log(i); //ReferenceError: i is not defined
var i;
var fn = function() {
var i = 1; //fn.i = 1;
}
console.log(i) //prints undefined
As Sebastien C. has already told you, your example code dosn't do what you want it to do. for (var i=0; i< 10; i++); means for (var i=0; i< 10; i++) {/*do nothing*/}. If you remove the ;, you'll notece your function will return 0, because the return keyword stops the function, and it return the value, no other operations will be executed, your loop will run only once.
Also, you should use ++i.
Yes Javascript is interpreted and whenever is finds a var declared/undeclared, it declares it and then performs the operations or in technical terms it does var hoisting. So now the variable is declared, but is undefined.
So any operation done on it (other than assignment) will result in its value being undefined only. eg;
{
x++ ;
var x = 10 ;
console.log(x);
}
will print 10. So you can think of it as
{
var x = undefined; \\variable hoisted at beginning of block
x++ ;
x = 10 ;
console.log( x ); \\ x = 10
}
I'm working through the end of the first example in Chapter 4 Eloquent Javascript. Here is the full piece of code (It's the last piece that I have questions regarding but I attached the first portion for reference).
var journal = [];
function addEntry(events, didITurnIntoASquirrel) {
journal.push({
events: events,
squirrel: didITurnIntoASquirrel
});
function phi(table) {
return (table[3] * table[0] - table[2] * table[1]) /
Math.sqrt((table[2] + table[3]) *
(table[0] + table[1]) *
(table[1] + table[3]) *
(table[0] + table[2]));
}
function hasEvent(event, entry) {
return entry.events.indexOf(event) != -1;
}
function tableFor(event, journal) {
var table = [0, 0, 0, 0];
for (var i = 0; i < journal.length; i++) {
var entry = journal[i], index = 0;
if (hasEvent(event, entry)) index += 1;
if (entry.squirrel) index += 2;
table[index] += 1;
}
return table;
}
function gatherCorrelations(journal) {
var phis = {};
for (var entry = 0; entry < journal.length; entry++) {
var events = journal[entry].events;
for (var i = 0; i < events.length; i++) {
var event = events[i];
if (!(event in phis))
phis[event] = phi(tableFor(event, journal));
}
}
return phis;
}
var correlations = gatherCorrelations(JOURNAL);
console.log(correlations.pizza);
My questions are:
What is the purpose of the .events in
var events = journal[entry].events;
Does it call on itself as a recursion? If so why? Couldn't we have just had journal[entry] and the function would run calling on the entry from the tableFor function? Does it call back to the AddEntry function (where the events variable was established) in an important way?
What is the purpose of (!(event in phis)).
I read it as : if event in phis is true then flip it to be not true and then trigger necessary phi calculation. Wouldn't it make more sense to eliminate the ! (does not equal) or that piece of code altogether? If we already have a for loop won't the function run on it's on until the max length of journal and stop?
var events = journal[entry].events; you are getting the events object from the object at index entry in the array journal and assigning it to a temporary variable called events.
This is just done for convenience so you don't have to keep referring to journal[entry].events. For example, later on it has this line:
var event = events[i];
which would become:
var event = journal[entry].events[i];
Without the assignment to a temporary variable.
if(!(event in phis)) it's testing to see if the object phis does not have a property with the name contained in the variable event. If the object doesn't already have that property, it adds it with the next line:
phis[event] = phi(tableFor(event, journal));
See in operator
Here's a very simple snippet of code to help understand the in operator:
var foo = {};
console.log("bar" in foo); // logs "false" because foo doesn't have a "bar" property
foo.bar = 1; // or foo["bar"] = 1;
console.log("bar" in foo); // logs "true" because foo now has a "bar" property
What is the purpose of the .events in
var events = journal[entry].events;
The purpose of this declaration conforms with 2 concepts of scripting convenience and economy. Every level of an object depth adds to the overall recall time when called. Certainly modern browsers have done much to flatten an objects variable stack, but if you think about it logically, any call to say object1.object2["Memeber3"].object4 has to go through 4 steps to get to the value itself. Flattening the value to a local object is more economic. Second, the readability (and therefore maintainability) of the code is enhanced in that you don't have the extra "journal[entry]." clogging up your expressions. As a general rule of thumb, if you are going to use a member of an object more than once in a block, then you should create a local variable of that member.
What is the purpose of
(!(event in phis)).
The purpose of this evaluation is to determine if a particular member(event) is NOT in the object(phis). In this example, the next line creates that member if it is indeed missing.