JavaScript exercise issue - javascript

i'm a novice in this world...so trying to begin, I started with an online tutorial. The exercise it's simple, but i can´t get the "empate" text on screen if the condition exists. Can you help me to know whats wrong?:
var usuarioElige = prompt("piedra, papel o tijera?");
var computadoraElige = Math.random();
if (computadoraElige <= 0.34) {
computadoraElige = "piedra";
} else if(computadoraElige <= 0.67) {
computadoraElige = "papel";
} else {
computadoraElige = "tijera";
}
var comparar = function (usuarioElige,computadoraElige) {
if (usuarioElige === computadoraElige) {
return "¡Es un empate!";
}
};

You never call the function that prints out the "enpate" message. Try this version:
var usuarioElige = prompt("piedra, papel o tijera?");
var computadoraElige;
var d = Math.random();
if (d <=0.34){
computadoraElige = "piedra";
}else if(d <=0.67){
computadoraElige = "papel";
}else{
computadoraElige = "tijera";
}
var comparar = function (x,y){
if (x===y){
alert("¡Es un empate!");
}
};
comparar(usuarioElige, computadoraElige)
Note the added call to the function at the end and that I renamed the parameters of the comparar function to "x" and "y" to avoid confusion (it also works if you stay with the old name).
Another thing is that I put the random number for the computer in a separate variable. It can be confusing if the same variable means two different things depending on what part of the program you are on.
I also improved the whitespace indentation of your program. Programs are easier to understand if they are well indented :)

You're missing:
comparar(usuarioElige, computadoraElige);
At the end of the code

Related

Cannot set inner property of null

I'm trying to make an app that will help me with my workouts and help me constantly lift more so that I can get stronger. I keep getting the error "Cannot set inner property of null" on the very bottom when I try to output the variables to the HTML. It's the code under the last section of comments that I am getting the error. Can some give me some guidance on how to fix this?
//Get the variables from the user. This will be the previous exercise or the exercise that the user has performed
const userSet = document.getElementById("set-user-1");
const userReps = document.getElementById("reps-user-1");
const userWeight = document.getElementById("weight-user-1");
var futureSet;
var futureReps;
var futureWeight;
//Define the functions that need to be done between the previous exercise and the next exercise
function getNewSet(previousSet) {
return previousSet;
}
function getNewRep(previousReps){
if(previousReps < 12) {
return previousReps + 2;
} else {
previousReps = 6;
return previousReps;
}
}
function getNewWeight(previousReps, previousWeight) {
if(previousReps < 12){
return previousWeight;
} else {
previousWeight = previousWeight + 10;
return previousWeight;
}
}
//Make a function that runs all the functions with the user input
function getNewWorkout() {
futureSet = getNewSet(parseInt(userSet));
futureReps = getNewRep(parseInt(userReps));
futureWeight = getNewWeight(parseInt(userReps, userWeight));
return futureSet;
return futureReps;
return futureWeight;
}
//Output will go to the future exercise dividers
document.getElementById("future-sets").innerHTML = futureSet;
document.getElementById("future-reps").innerHTML = futureReps;
document.getElementById("future-weight").innerHTML = futureWeight;
The error is in the last two lines of this function. A function can only return one value, it might be worth putting all the values in an array
and then returning it.
//Make a function that runs all the functions with the user input
function getNewWorkout() {
futureSet = getNewSet(parseInt(userSet));
futureReps = getNewRep(parseInt(userReps));
futureWeight = getNewWeight(parseInt(userReps, userWeight));
return futureSet;
//error here
return futureReps;
return futureWeight;
}
So you can update your code as follows to return object,
function getNewWorkout() {
const futureSet = getNewSet(parseInt(userSet));
const futureReps = getNewRep(parseInt(userReps));
const futureWeight = getNewWeight(parseInt(userReps, userWeight));
return {futureSet, futureReps, futureWeight};
}
Which you can access through object.
This kind of error comes when you load the script before DOM is ready. You can try to load the script at the end of the HTML, usually in footer. This should fix your error.
Also, please call the function 'getNewWorkout()' in your script to get expected output.

Local variables giving global trouble

I'm a JS super n00b.
I asked about an aspect of this problem in this post (Puzzling behavior from IF ( ) statement) on IF statements but it looks like the actual issue is related to the scope of a variable I've created. It seems that after declaring (what I think is) a global variable, other functions in the code cannot access the variable.
I'm doing JS project/program that prompts a user to input a word and the program reverses the word input.
In the previous post (PP) a user correctly determined that I was getting the 'false' console message (see code) no matter what the length of the word input because I was assigning value the variable when the page loads but not reading it again when the user clicks the button on the page.
If the variable 'word' is local I'm only able to get a 'false' console message and when the variable 'word' is global I'm only able to get a 'ReferenceError.'
Any ideas anyone has are greatly appreciated.
See JS code below:
var word = document.getElementById('wordChoice').value;
var lttrs = [];
function flipFail () {
alert("Please enter a word of at least two characters.");
console.log(false);
var inputErrArr = ['has-error', 'has-feedback'];
var inputErrFdbk = ['glyphicon', 'glyphicon-remove'];
wordChoice.style.backgroundColor = "#FFDBAA";
for (var i = 0; i < inputErrArr.length; i ++) {
addClass(wordInput, inputErrArr[i]);
}
for (var i = 0; i < inputErrFdbk.length; i ++) {
addClass(glyph, inputErrFdbk[i]);
}
document.getElementById('wordChoice').value = " ";
} // END flipFail()
function flipSuccess (){
for (var i = 0; i < word.length; i ++) {
lttrs.push(word.charAt(i));
}
lttrs.reverse();
var reversedWord = lttrs.join('')
alert("Your reversed word is: " + reversedWord);
console.log(true);
document.getElementById("flip").innerHTML = "Flip Again!";
document.getElementById('wordChoice').value = " ";
} // EN flipSuccess ()
function flipChk () {
if (word.length < 2) {
flipFail ();
} else {
flipSuccess ();
}
}
See fully implemented code here: http://supsean.com/supsean/flipr/flipr.html
You need to set word in flipChk(). You're setting it when the page is first loaded, before the user has entered anything into the form, not when the user clicks on the Flip button.
Then, instead of using a global variable, pass it as an argument to the function. In general, avoid using global variables unless you really have to.
function flipChk () {
var word = document.getElementById('wordChoice').value;
if (word.length < 2) {
flipFail ();
} else {
flipSuccess (word);
}
}
function flipSuccess (word){
var lttrs = [];
for (var i = 0; i < word.length; i ++) {
lttrs.push(word.charAt(i));
}
lttrs.reverse();
var reversedWord = lttrs.join('')
alert("Your reversed word is: " + reversedWord);
console.log(true);
document.getElementById("flip").innerHTML = "Flip Again!";
document.getElementById('wordChoice').value = " ";
} // EN flipSuccess ()

What Chrome does instantly, Firefox takes 30 seconds

Currently, I am creating a program that will turn source code into highlighted HTML-like text. When I tested it, though, I found some strange results. On Chrome, the program will parse 1000 lines of source almost instantaneously. Firefox, however, takes 30 seconds to parse the same 1000 lines. And, ironically enough, IE10 only takes 18 seconds.
Now, I understand that different browsers implement javascript differently and that Chrome tends to be faster, but I do not understand why it is taking Firefox over 30 times longer. I ran a raw while-loop test of 10,000,000,000 operations on each, and it took FF 14 seconds and Chrome 12. Therefore, I am inclined to believe that somewhere in my code is something that takes Firefox an abnormally long time to accomplish; I've done research, but nothing I've found so far would indicate the large discrepancy I am seeing.
So, does anyone have any suggestions as to what may be causing this? I've posted the problem area of the code below (commenting this portion out causes both browsers to parse instantaneously). start and end are both regular expressions; istream is where the source code is coming from, and ostream is where parsed code goes to. istream.read() calls the String slice() method. Finally, this function is called many many times throughout the program.
function(buffer, istream, ostream){
if(start.test(istream.content)){
buffer = istream.read();
ostream.write('[[span class="' + type + '"]]' + buffer);
do{
/* Special Cases */
if(end.test(ostream.content + istream.peek()) && (istream.peek() == "\n" || istream.peek() == " " || istream.peek() == "\t")){
include = true;
break;
}
else if(istream.peek() == "\n"){
istream.read();
ostream.write('[[/span]][[/span]]\n[[span class="line"]][[span class="' + type + '"]]');
continue;
}
else if(istream.peek() == "\t"){
istream.read();
ostream.write("#<    >#");
continue;
}
else if(istream.peek() == " "){
istream.read();
ostream.write("#< >#");
continue;
}
ostream.write(istream.read());
} while(!istream.isEmpty() && !end.test(ostream.content));
if(include || istream.isEmpty())
ostream.write('[[/span]]');
else{
var ending = ostream.content.length-1;
while(!end.test(ostream.content.substr(ending)))
--ending;
istream.content = ostream.content.substr(ending) + istream.content;
ostream.content = ostream.content.substring(0, ending) + '[[/span]]';
}
return true;
}
return false;
}
Any insight would be greatly appreciated, and if you have any queries as to how certain aspects of this are implemented, I will oblige. Thanks in advance.
Definition of istream and ostream objects:
function IOstream(init){
this.content = init;
this.read = function(){
var tmp = this.content.charAt(0);
this.content = this.content.slice(1);
return tmp;
};
this.peek = function(){ return this.content.charAt(0); };
this.write = function(str){ this.content += str; };
this.isEmpty = function(){ return this.content.length == 0; }
}
I think it is because on every .read() call you make content.slice(1) and every time it copies the entire string but first character and can take a lot of time.
Try modifyin your IOStream class like this:
function IOstream(init){
this.content = init;
this.cursor = 0;
this.read = function(){
var tmp = this.content.charAt(this.cursor);
this.cursor++;
return tmp;
};
this.peek = function(){ return this.content.charAt(this.cursor); };
this.write = function(str){ this.content += str; };
this.isEmpty = function(){ return this.cursor>=this.content.length; }
}
I think it will solve your speed problem in all browsers.
Noticed you're using loose equality. I would start there and change the == to === and see if it makes a difference.
Here is a jsperf of loose vs strict: http://jsperf.com/performance-of-loose-vs-strict-equality

Is there a way to manipulate included JS without eval()?

I know lots of people think "eval is evil," but I have to accomplish something and I'm having trouble figuring out how to do it without eval().
The situation is this: an external file (I have no control over it--EDIT: but it's not user-generated. It's from a trusted source! I imagine this is important) is spitting out JavaScript for me to use. This JavaScript contains some nice JSON data (which is what I need to get), but it's flanked by ordinary JavaScript statements declaring variables and calling functions and such. It looks kinda like this:
var foo = new Object();
foo['KEY'] = {Field1: 'Value1', Field2: 'Value2'};
eval('fooFunction(foo)');
If I eval() this, I can just parse foo['KEY'] and be done with it. The only way I can think to do this without eval() is with a bunch of annoying replace()ments, which hardly seems better. Am I missing some obvious way to do this? Most of the "you don't have to use eval()" alternatives I usually see assume I have complete control over everything, but in this case I have to work around this existing code.
EDIT: I should add that this code is being obtained via an AJAX call from a proxy script (cross-domain stuff), so none of the variables are accessible. If they were, I'd obviously just be able to parse foo['KEY'] and be on my merry.
SECOND EDIT: nothing conclusive yet! I'm getting dangerously close to concluding that eval() is the way to go. Can you stomach this outcome? I'm about to give in to evil(). Somebody stop me, because it's looking like the only way.
The external code better send back valid JSON. The value in your example is not valid JSON, as the keys must be wrapped with double quote.
I came up with small pure JavaScript parser, that can handle simple invalid JSON by adding double quotes by itself. It currently won't support non string values.
function ParseRawJSON(rawCode) {
var arrCandidates = [];
var lastOpenBracketIndex = -1;
for (var i = 0; i < rawCode.length; i++) {
var curChar = rawCode.charAt(i);
if (curChar === "}") {
if (lastOpenBracketIndex >= 0) {
arrCandidates.push(rawCode.substr(lastOpenBracketIndex, i - lastOpenBracketIndex + 1));
lastOpenBracketIndex = -1;
}
} else if (curChar === "{") {
lastOpenBracketIndex = i;
}
}
var arrJsonObjects = [];
for (var i = 0; i < arrCandidates.length; i++) {
var currentJSON = null;
try {
currentJSON = JSON.parse(arrCandidates[i]);
} catch (e) {
//try fixing
var fixedCandidate = TryFixJSON(arrCandidates[i]);
if (fixedCandidate) {
try {
currentJSON = JSON.parse(fixedCandidate);
} catch (e) {
currentJSON = null;
}
}
}
if (currentJSON != null) {
var keys = [];
for (var key in currentJSON)
keys.push(key);
if (keys.length > 0)
arrJsonObjects.push(currentJSON);
}
}
return arrJsonObjects;
function Trim(s, c) {
if (c instanceof Array) {
for (var i = 0; i < c.length; i++)
s = Trim(s, c[i]);
return s;
}
if (typeof c === "undefined")
c = " ";
while (s.length > 0 && s.charAt(0) === c)
s = s.substr(1, s.length - 1);
while (s.length > 0 && s.charAt(s.length - 1) === c)
s = s.substr(0, s.length - 1);
return s;
}
function TryFixJSON(strBlock) {
if (strBlock.indexOf(":") <= 0)
return false;
strBlock = strBlock.replace("{", "").replace("}", "");
var mainParts = strBlock.split(",");
for (var i = 0; i < mainParts.length; i++) {
var currentPart = Trim(mainParts[i]);
if (currentPart.indexOf(":") <= 0)
return false;
var subParts = currentPart.split(":");
if (subParts.length !== 2)
return false;
var currentKey = Trim(subParts[0], [" ", "'", "\""]);
var currentValue = Trim(subParts[1], [" ", "'", "\""]);
if (currentKey.length === 0)
return false;
subParts[0] = "\"" + currentKey + "\"";
subParts[1] = "\"" + currentValue + "\"";
mainParts[i] = subParts.join(":");
}
return "{" + mainParts.join(", ") + "}";
}
}
This will just look for anything between { and } and try to parse as JSON. No eval, in case of failure it'll just ignore the invalid block. Success? Great, it will return plain array of the valid JSON's it found.
Usage example:
var rawCode = "var foo = new Object(); { dummy here }}} function boo() {}" +
"foo['KEY'] = { \"Field1\": \"Value1\", \"Field2\": \"Value2\"}; hello {\"foo\": \"bar\"} and it's over ";
var jsonObjects = ParseRawJSON(rawCode);
for (var i = 0; i < jsonObjects.length; i++) {
for (var key in jsonObjects[i]) {
var value = jsonObjects[i][key];
//got key and value...
}
}
Live test case, using fixed version of your sample code.
A generally safer alternative to using eval is creating a new Function and passing it the string function body. That way (unless something is explicitly acessing the window object) you won't have access to the global scope and can keep it encapsulated in the function scope.
Let's say the first two lines of your example code are the JavaScript that you'd like to evaluate, if you know the name of the variable you want to retrieve as a JSON object you can just return it at the end of the created function and then call it:
var js = "var foo = {}; foo['KEY'] = {Field1: 'Value1', Field2: 'Value2'};";
var fn = new Function(js + ';return foo;');
var result = fn();
console.log(JSON.stringify(result));
This is also what MDN suggests doing in the documentation for eval:
More importantly, third party code can see the scope in which eval() was invoked, which can lead to possible attacks in ways of which the similar Function is not susceptible.
If the JSON contains just data and not functions you can use JSON.parse()
See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse for more detailed info.
As the method has been placed in to the global, then you can do
window["fooFunction"](foo)

setInterval only working inside of if(){} block

So I think there is something key to be picked up from this situation I encountered and was hoping some experience could explain it.
When I run this code, it does NOT work:
t5 = "nikolas"+t4;
setInterval(adds,250);
function adds(){
if (t4 < 100){
t4=t4+1;
}
else{
return;
}
};
this does DOES work:
t5 = "nikolas"+t4;
adds(t4);
function adds(a){
if (a < 100){
a=a+1;
setInterval(t4=a,250);
}
else{
return;
}
};
TL;DR: setInterval seems to work inside the if block but not outside. When it works it displays nikolast4 where t4 is an integer that 'ticks' from 1-100 (eg.strong text nikolas0 nikolas1 nikolas2 nikolas3 nikolas4)
Also this code (due to the application I am programming in) is supposed to refresh every 250ms (but take the whole refreshing part with a grain of salt, not totally 100% sure about that).
The code below is fully functionnal, and looks very much like your non-working example.
You can check here :
http://jsbin.com/ofezip/1/edit
So i guess you have an issue with the scope of your variables.
window.onload = function() {
var myOutput = document.createElement("output");
document.body.appendChild(myOutput);
var t4 = 0;
var helloInterval = setInterval(adds,250);
function adds(){
if (t4 < 10){
t4++;
myOutput.value = "hello " + t4;
}
else {
myOutput.value = "goodbye" ;
clearInterval(helloInterval);
return;
}
}
};

Categories

Resources