Why is my Javascript logging Unlogged values to the CodeCademy Console? - javascript

This has happened many times and I've just ignored it until now, however it's bugging me because I'm not sure if my code will be correct.
The issue is that when I console.log(TextA) or (TextB) and then put a value into a variable, the console will log the value that I push to the variable.
Example below:
My CodeCademy code is:
var slaying = true;
var youHit = (Math.floor(Math.random() * 2) == 1);
var damageThisRound = Math.floor(Math.random()*5 + 1);
var totalDamage = 0;
while (slaying) {
if (youHit) {
console.log("Congrats, you hit");
} else {
console.log("You were defeated by the dragon");
}
slaying = false;
}
And my console log is:
Congrats, you hit
false
Does this happen to anyone else? is it just an error with the CodeCademy system or is my Javascript not correct?

This is because their interpreter, much like the browser console, evaluates all of the code you put into it and all operations in javascript have a return value. Try this for example:
var y = (foo = 'x');
console.log(y);
The assignment operation has a return value. This becomes more apparent when you use things like eval and new Function to evaluate code, because they will show you the value of the last interpreted line of code, then you see that even do..while statements have a return value. If you change the last line of your while statement, you will see that the last value is logged instead of false.
Here is another example using eval that might demonstrate better:
eval('var foo = 0; i = 0; while( i < 2 ) { i++; foo = i * 9; } ')
Note that I didn't log anything explicitly there, but because foo = i * 9 (where i = 2) was the last line evaluated, you will see 18 in your console. Also note that if I had included var in that statement, you would see 1 instead, because i++ would be the last operation that returned a value (to add to the confusion, var assignments return undefined).

Related

call for loop through function with parameters

I have the below for loops, I have it manytime in my code, with different variables name, I would put it in a function with parameters and call it but it didn't work
for(let i = 0; i < inputs.length - 1; i++){
if(!nputs[i].value){
error += inputs[i].getAttribute('test') + " is blank";
isTrue = false;
}
}
Here what I did
let y = "";
let z = true;
function test(x,y,z){
for(let i = 0; i < x.length - 1; i++){
if(!x[i].value){
y += x[i].getAttribute('name') + " is blank !";
z = false;
}
}
}
let error = "";
let isTrue = true;
test(inputs,error,isTrue);
shall I do return in the function? if yes which return should I do?
Scope: when you define y and z outside the function (in the global scope presumably) they are different than the y and z defined in the parameter list of the function. The ones in the parameter list only exist within the body of the function. Changing the value of the parameter named y within the function does not change the value of the global variable y. So the simple answer to your question is, yes, you need to return something, since the value of the parameter y is lost when the function is done executing.
Give your variables descriptive names. Let the obfuscator do it's thing later.
function test(x,y,z) -> function valueTest(arr, err, success)
The boolean status and error string are redundant bits of information. If the error string is not empty, then the status is failure. So you don't need to return both a boolean and the string.
The status of the previous test is of no relevance to the next test. Therefore, z or success doesn't have to be passed in to the function each time, as it (or something like it) is really the desired output of the function, and each call of the function can be treated separately. If you want to combine the results from different tests then that should be the concern of whatever is calling this function - see separation of concerns and coupling
The only parameter the function actually needs is the value that is under test (the array).
When you write the function you define the return value, and thus you define how other code can decipher those results. The function itself doesn't have to do all the work of interpreting the results and building the error string. If your return value was just an array of name attribute values (of the elements of the test array that failed), the calling code could still process "success" or "failure". If the return value has one or more elements, or a length > 0 that would indicate failure.
Removing the redundant/unnecessary parameters and information, you'll have a function that looks something like this:
function valueTest(arr) {
let results = [];
for (let i = 0; i < arr.length - 1; i++){
if (!arr[i].value) {
results.push(arr[i].getAttribute('name'));
}
}
return results;
}
The caller can decipher and build an error message from that. It might make sense for the function to handle some of the additional work by returning <name> is blank! instead of just <name>, and then you just need to join the elements of the array.
...so within the function...
results.push(arr[i].getAttribute('name') + ' is blank!');
...and back in the global scope...
const error = valueTest(inputs).join(" ");
let success = error.length > 0;
5.If you want a running status indicator from different tests, evaluate an individual test's result, then logically AND that with the previous result.
const result1 = valueTest(inputs1).join(' ');
let success = results1.length > 0;
const result2 = valueTest(inputs2).join(' ');
success &= (results2.length > 0);
Seeing the issues with your code are handled in the comments, I present you a simpler method.
If you count the elements that have the attribute and are not empty and compare it to the length of all the inputs passed you will have a better test
const test = (inputs,attr) => [...inputs]
.filter(inp => inp.getAttribute(attr) && inp.value.trim() !== "").length === inputs.length;
const istrue = test(document.querySelectorAll("input"),"name")
isTrue will be true if all passed inputs has an attribute called name
You can also do
const elems = document.querySelectorAll("input[name]")
const isTrue = elems.filter(inp => inp.value.trim() !== "").length === elems.length

Getting the result of an if else statement out of scope in Javascript

In this code I currently have the value of the addToOutput variable trapped inside an if else statement in a way that I am unable to get that value of the variable outside to the statement. I wish to get this value out so that when the user enters a number (for example 930) the function will output 900+30+0. To compile the results I have the variable "output" but if its unable to get the value from addToOutput I will not be able to get the desired result how can I make it so the value of addToOutput will be in scope?
function expandedForm(num) {
let stringOfNumber = num.toString();
let numberArray = Array.from(stringOfNumber);
let zero = "0";
let output;
let addToOutput;
for (let i=0; i<numberArray.length; i){
let firstNumber = numberArray.shift();
let arraySize = numberArray.length;
ifElse(arraySize, firstNumber,zero)
output = output + addToOutput;
}
}
function ifElse (arraySize, firstNumber, zero, addToOutput){
if(arraySize > 0){
let numberOfZeros = zero.repeat(arraySize);
addToOutput=firstNumber+ numberOfZeros + " + ";
return(addToOutput);
}
else{
addToOutput = firstNumber;
return(addToOutput);
}
}
expandedForm(930);
Remove the addToOutput parameter from ifElse, and just return the value you want returned (see *** lines):
function ifElse (arraySize, firstNumber, zero){ // ***
if(arraySize > 0){
let numberOfZeros = zero.repeat(arraySize);
return firstNumber+ numberOfZeros + " + "; // ***
}
else{
return firstNumber; // ***
return(addToOutput);
}
}
Then when calling it, use that return value:
addToOutput = ifElse(arraySize, firstNumber, zero);
This is a programming fundamental (in JavaScript and many other languages): You pass data into a function, the function operates on the data, and returns the result. There's more to it than that, but that's the basic thing.
Returning the value is a very good way of doing it, as stated in the first answer. However, I thought it would be worth adding some information about arguments by reference and by value.
What are often called "primitive" types (strings, numbers, booleans, etc) are passed by value, meaning changes in the value are lost when you leave the function. But objects are passed by reference, meaning changes remain after the function returns. So in your example above, all those are being passed by value. But imagine you did this instead:
var o = {arraySize, firstNumber,zero, addToOutput};
console.log(o.addToOutput);
ifElse(o);
console.log(o.addToOutput); // value may be different now!
function ifElse (o) {
if(o.arraySize > 0){
let numberOfZeros = zero.repeat(o.arraySize);
o.addToOutput=o.firstNumber+ numberOfZeros + " + ";
}
else{
o.addToOutput = o.firstNumber;
}
}
Now you are passing an object o which contains your four parameters. And this is passed by reference, so changes will persist.
Again, this is just one more option to returning a value. If you need more than one return value it can be a helpful tool.

Recursion in JavaScript With IF and WHILE

I just come up with little strange behavior in Javascript Recursion. My code
var temp1 = function(maxLength,accNumber) {
if(accNumber.length < maxLength)
{
accNumber = '0'+accNumber;
temp1(maxLength,accNumber);
}
return accNumber;
};
console.log(temp1(5,"23"));
So Here I am expecting output as "00023" but its giving "023" which is not expected.
But same code with while loop I am getting expected output. I am not understanding why.
var temp1 = function(maxLength,accNumber) {
while(accNumber.length < maxLength)
{
accNumber = '0'+accNumber;
temp1(maxLength,accNumber);
}
return accNumber;
};
console.log(temp1(5,"23"));
Which give me output "00023" as expected.
In fact you are missing a return statement inside your if block:
var temp1 = function(maxLength,accNumber) {
if(accNumber.length < maxLength)
{
accNumber = '0'+accNumber;
return temp1(maxLength,accNumber);
}
return accNumber;
};
console.log(temp1(5,"23"));
So the code wasn't returning anything if the if condition was passed, that explains why you got 023 instead of 00023.
Change your recursive call from
temp1(maxLength,accNumber);
to
return temp1(maxLength,accNumber);
Without the new return above, your code is detecting that accNumber.length is less than maxLength and correctly adding a '0' to the front. However, your recursive call is not modifying the local variable accNumber, and not returning, so it is basically doing nothing. After the recursive call, the program will exit the if block, and return the original accNumber, which is 023.
In the if loop, it's detecting that the length is smaller than maxLength, so it adds the 0 at the start and is done with the loop. It doesn't check again, if the length is still smaller. So after adding a single 0, it is done with the loop and returns output.
On the other hand the while loop will keep checking after each iteration.
Your function with if should look something like this:
function(maxLength,accNumber) {
if(accNumber.length < maxLength)
{
accNumber = '0'+accNumber;
return temp1(maxLength,accNumber);
}
return accNumber;
};
This question appears to be a duplicate of Strange result using recursion with while loop, but I wanted to play with this to see if type coercion might be involved.
I have re-authored this here, uncomment the console.logs to see more detail: this jsfiddle.
This is a scope issue from what I can tell, the if is creating a new scope each time and upon finally exiting, returns the first recursive value for accNumber (023) rather than the innermost recursive scope value (00023). The difference is that the while loop doesn't lose scope in the same way the if version of this does.
var temp1 = function(maxLength,accNumber) {
if(accNumber.length < maxLength) // There is no iteration
{
accNumber = '0' + accNumber;
temp1(maxLength,accNumber); // This creates a new scope
}
return accNumber; // You're only returning the initial iteration result
};
console.log(temp1(5,"23"));
But in the while version...
var temp1 = function(maxLength,accNumber) {
while(accNumber.length < maxLength)
{
accNumber = '0'+accNumber;
temp1(maxLength,accNumber); // Since it is in a while, scope is maintained
}
return accNumber;
};
console.log(temp1(5,"23"));

Setting variable to existing value versus return?

In Javascript, I have a function that sets a variable. If the function tries to set the variable to its current value, is it more "efficient" to break out of the function, or let the function re-set the variable's value?
Example
var a;
function setStuff(x) {
if (a == x) { return; }
a = x;
}
versus
var a;
function setStuff(x) {
a = x;
}
This function will be called on page scroll, so it will be called at a high frequency.
I don't think the issue is "efficiency".
I do however think there's a practice at play here, which is to generally not manipulate values outside the scope of the function. Having many functions like these in your application will drive you nuts, wondering which function is changing what.
Instead return a new value.
var setStuff = function() {
return newValue;
}
var a = setStuff();
I wrote a simple test snippet:
var a;
function setStuffCheck(x) {
if (a == x) { return; }
a = x;
}
function setStuff(x) {
a = x;
}
function benchmark(func){
var startTime = Date.now();
var callCount = 1000000;
for(var i = 0; i < callCount; i++){
func(10);
}
console.log((Date.now() - startTime) + "ms for "+callCount+" calls setting always the same value");
startTime = Date.now();
for(var i = 0; i < callCount; i++){
func(i);
}
console.log((Date.now() - startTime) + "ms for "+callCount+" calls setting always different values");
}
benchmark(setStuffCheck);
benchmark(setStuff);
By copying and pasting it in the console (Firefox 46.0.1), I have something like this:
138ms for 1000000 calls setting always the same value
216ms for 1000000 calls setting always different values
77ms for 1000000 calls setting always the same value
78ms for 1000000 calls setting always different values
So the second way seems to be always better. But the results may be different on each computers. However, the difference is noticable only for 1 millions of calls (try changing it to 1000, there'll be no differences).
The second option makes more sense to me and is more viable as there is very less logic written as compared to the first one as it is checking whether two values are equal or not , whereas in the second option its just re-assigning the variable to a new value.
if condition is always slower compared to when just assigning a new value . So i think you should go with second option.
There are potentially two factors that will likely drown out any practical performance difference between the two options. In practice, I would suggest that you use the version that is the easiest to understand and explain to others. I think that would probably be the unconditional update but it would be more up to you.
The two things that are likely going to obfuscate any real differences are:
What else are you doing in the function
What effect branch prediction has on your conditional.
Now, specifically to the question of what version is faster. I have set up the following test with each option executed a million times with 10 runs of each test. The global is set to itself 1 in 10 times but you can change that to some other frequency by setting aNew
var a = 10;
var ittr = 1000 * 1000;
function getRandomIntInclusive(min, max) { return Math.floor(Math.random() * (max - min + 1)) + min; }
function set1(x){
if (a === x){ return; }
a = x;
}
function set2(x){
a = x;
}
for (var j = 0; j < 10; j++){
var start = performance.now();
for (var i = 0; i< ittr; i++){
var aNew = a - 10 + getRandomIntInclusive(1,19);
set1(aNew);
}
console.log("conditional : " + (performance.now() - start));
}
for (var j = 0; j < 10; j++){
var start = performance.now();
for (var i = 0; i< ittr; i++){
var aNew = a - 10 + getRandomIntInclusive(1,19);
set2(aNew);
}
console.log("unconditional : " + (performance.now() - start));
}
Your results may vary but the I see conditional set() averages about 18 after settling down. The unconditional about the same, maybe 17.5.
Note that the vast bulk of the time here is taken by the call to random(). If you consistently just set the global to itself both functions time at around 1.8 rather than 18, suggesting that whatever else you might do in your set() is likely to obfuscate any performance difference.
The two do not have necessarily have identical results. Consider this series of calls:
var a;
function setStuff(x) {
if (a == x) { return; }
a = x;
}
setStuffCheck(0) ;
setStuffCheck('0');
console.log(a);
Output is not '0', but 0.
For a good comparison, the setStuffCheck function should use the strict equality operator ===.
In my tests in FireFox I see the performance of both functions show very little difference. setStuffCheck seems to take slightly more time to execute than setStuff when the argument has a different value than a, but it is the opposite (also slightly) when the values are the same. The difference in either way is in the order of 2%, which is the kind of fluctuations you get anyway on a typical device/PC for other causes, that have nothing to do with the code.
Anyway, this also means that this slight performance difference will depend on how often you expect to call the function with an argument that is equal to a.
However, the difference is only noticeable when you would do hundreds of millions of calls. If you don't have that many calls, then don't even bother and choose for setStuff.

javascript (nodejs) while loop bug

running the following code in nodejs cli:
var my_function = function() {
var next_value = 1
, value = undefined
, difference = undefined
, prev_difference = undefined
while ((typeof prev_difference === 'undefined') || (prev_difference > 0)) {
value = next_value
next_value = 2
difference = next_value - value
if (difference > prev_difference) {
throw new Error('Diminishing')
}
prev_difference = 0
}
return next_value
}
for (var i = 0; i< 300; i++) { console.log(i); console.log(my_function()) }
At iteration 282 of the loop I start getting the value '1' instead of '2'. Can't for the life of me understand why. This chunk of code is a reduction from something else I've been working on, hence the seemingly unnecessary if statement within the loop. There are a few ways to change this code such that the execution path does not get screwed up, but I'd like to understand why it's breaking with the current setup.
Also, if you have any tips for tools that could aid me in debugging something like this in the future I would be very grateful. For the most part I used console.log to narrow this down.
node.js version v0.8.6. Running on Mac OSX version 10.7.5.
Thanks
If you take out the IF statement it is gonna be fine, it will return only '2' on every iteration. The variable prev_difference is 'undefined' every time and this seems to cause issues.

Categories