I am writing code to learn defensive error handling in javascript.
The program calculates distance, time or speed depending on the user's choice. This bit works fine.
I then tried to add a try catch statement under the prompt-time function and this worked.
So I took that code and tried making it into one function rather than typing it out thrice.
The idea is that if the user enters something that is not a number or blank the program will keep asking for a number until they do.
But now whenever I enter something that is not a number the while loop does not show the prompt and loops indefinitely. I need a while loop as using an if statement makes the program go on without the correct output.
I am not sure why this is happening.
ask = prompt('Calculate distance(d), time (t) or speed (s)')
function notNumber(input) {
while (true)
try {
let input = Number(prompt('Enter your ' + input))
if (isNaN(input) == true || input == "") {
throw "Invalid Input";
}
return input;
}
catch (err) {
console.log(err);
}
}
function promptTime(time) {
time = Number(prompt('Enter your Time'))
if (isNaN(time)) {
notNumber(time)
}
return time;
}
function promptSpeed(speed) {
speed = Number(prompt('Enter your Speed'))
if (isNaN(speed)) {
notNumber(speed)
}
return speed;
}
function promptDistance(distance) {
distance = Number(prompt('Enter your distance'))
if (isNaN(distance)) {
notNumber(distance)
}
return distance;
}
if (ask == 'd') {
let time = promptTime()
let speed = promptSpeed()
distance = time * speed
if (distance == Number) {
console.log('Your distance is ' + distance)
}
if(isNaN(distance)) {
notNumber(distance)
}
}
else if (ask == 't') {
let distance = promptDistance()
let speed = promptSpeed()
time = distance / speed
console.log('Your time is ' + time)
if(isNaN(time)) {
notNumber(time)
}
}
else if (ask == 's') {
let distance = promptDistance()
let time = promptTime()
speed = distance / time
console.log('Your speed is ' + speed)
if(isNaN(speed)) {
notNumber(speed)
}
}
else {
console.log('Please enter a measurement!')
}
Changes:
Redefined the promptNumber function from 'input' to a different name ('variable')
Added refer variable to get the name of the desired calculation (time, speed or distance)
Note that I tried calling 'refer' 'name'. But name came up as deprecated.
Got rid of the nested if statements as they are now redundant. For example:
else if (ask == 't') {
let distance = promptDistance()
let speed = promptSpeed()
time = distance / speed
console.log('Your time is ' + time)
/* Got rid of statements like these
if(isNaN(time)) {
notNumber(time)
}
*/
}
The finalised code is:
ask = prompt('Calculate distance(d), time (t) or speed (s)')
function promptNumber(variable) {
while (true) {
try {
let input = Number(prompt(`Enter a number for ${refer}`));
if (input == "" || isNaN(input)) {
throw "Invalid Input";
}
return Number(input);
} catch (err) {
console.log(err);
}
}
}
function promptTime(time) {
time = Number(prompt('Enter your Time'))
refer = 'time'
if (isNaN(time)) {
time = promptNumber(time)
}
else {
return time;
}
return time;
}
function promptSpeed(speed) {
speed = Number(prompt('Enter your Speed'))
refer = 'speed'
if (isNaN(speed)) {
speed = promptNumber(speed)
}
else {
return speed;
}
return speed;
}
function promptDistance(distance) {
distance = Number(prompt('Enter your distance'))
refer = 'distance'
if (isNaN(distance)) {
distance = promptNumber(distance)
}
else {
return distance;
}
return distance;
}
let refer = ''
if (ask == 'd') {
let time = promptTime()
let speed = promptSpeed()
distance = time * speed
console.log('Your distance is ' + distance)
}
else if (ask == 't') {
let distance = promptDistance()
let speed = promptSpeed()
time = distance / speed
console.log('Your time is ' + time)
}
else if (ask == 's') {
let distance = promptDistance()
let time = promptTime()
speed = distance / time
console.log('Your speed is ' + speed)
}
else {
console.log('Please enter a measurement!')
}
Related
const getSleepHours = (day) => {
switch (day) {
case "monday":
return 6;
break;
case "tuesday":
return 7;
break;
case "wednesday":
return 9;
break;
case "thursday":
return 8;
break;
case "friday":
return 9;
break;
case "saturday":
return 10;
break;
case "sunday":
return 8;
break;
default:
console.log("Error");
}
};
console.log(getSleepHours("sunday")); // should print the # hours assigned to tuesday
const getActualSleepHours = () => {
const totalHours =
getSleepHours("monday") +
getSleepHours("tuesday") +
getSleepHours("wednesday") +
getSleepHours("thursday") +
getSleepHours("friday") +
getSleepHours("saturday") +
getSleepHours("sunday");
return totalHours;
};
const getIdealSleepHours = (idealHours) => idealHours * 7;
//console.log(getActualSleepHours());
//console.log(getIdealSleepHours());
const calculateSleepDebt = () => {
const actualSleepHours = getActualSleepHours();
const idealSleepHours = getIdealSleepHours(8);
const SleepDebt = idealSleepHours - actualSleepHours;
console.log(SleepDebt);
let time = '';
const SleepHourFunction = () => {
if (SleepDebt > 1) {
return time = ("hours");
} else if (SleepDebt < 1) {
return time = ("hours");
} else if (SleepDebt == 1) {
return time = ("hour");
} else {
return 'error';
}
}
SleepHourFunction();
if (actualSleepHours == idealSleepHours) {
console.log("You got the perfect amount of sleep. Keep it up!");
} else if (actualSleepHours > idealSleepHours) {
console.log(
"You got more sleep than neccessary. You are over by " + -SleepDebt + " " + time + "."
);
} else if (actualSleepHours < idealSleepHours) {
console.log(
"You need more sleep, get some rest. You are under by " + SleepDebt + " " + time + "."
);
} else {
console.log("Error");
}
};
calculateSleepDebt();
Here is the whole code.
const SleepDebt = idealSleepHours - actualSleepHours;
console.log(SleepDebt);
let time = '';
const SleepHourFunction = () => {
if (SleepDebt > 1) {
return time = ("hours");
} else if (SleepDebt < 1) {
return time = ("hours");
} else if (SleepDebt == 1) {
return time = ("hour");
} else {
return 'error';
}
}
SleepHourFunction();
This is what I tried. I am doing one of the Codecademy projects rn, almost finished, but I want to create a function where if the sleep debt hours is = 1, then it returns the singular term 'hour', and if it's multiple then returns the plural term 'hours'. It just keeps repeating hours regardless, I don't see why the function isn't executing how I want it. Does anybody have a clue? I am new to coding, so if this is a really simple problem, please be patient with me. Cheers.
.......................................
!UPDATE. played around with it and took in the feedback I figured it out
this is how I fixed it
if (SleepDebt > 1) {
return time = ("hours");
} else if (SleepDebt === 1 || SleepDebt === -1) {
return time = ("hour");
} else if (SleepDebt < 1) {
return time = ("hours");
} else {
return 'error';
}
SleepHourFunction();
Thanks so much for your answers guys it helped! :)
I have a simple bit of code for reading input for a terminal-based build script.
async function readLine(): Promise<string> {
return new Promise<string>(resolve => {
const callback = (data: any) => {
process.stdin.off('data', callback);
resolve(data.toString().trim());
};
process.stdin.on('data', callback);
});
}
This works well enough, but I'd like to be able to detect if an up-arrow is pressed so a user can back up to a previous prompt.
Every example I've seen so far that would allow me to detect an up-arrow key requires totally abandoning line-based input, instead handling all input one character at a time. I'd rather not do that.
What I'd like is to have a callback that's triggered only by the up-arrow key (and maybe other special keys later on), with all other keys coming through the usual 'data' callback, one full Enter-terminated line at a time.
Is there a way to do this?
Having found no better answer, I settled for handling all characters one character at a time, and writing my own terminal line input routine.
import * as readline from 'readline';
import { Key } from 'readline';
readline.emitKeypressEvents(process.stdin);
process.stdin.setRawMode(true);
function write(s: string): void {
process.stdout.write(s);
}
async function readUserInput(): Promise<string> {
return new Promise<string>(resolve => {
let buffer = '';
let length = 0;
const clearLine = () => write('\x08 \x08'.repeat(length));
const callback = (ch: string, key: Key) => {
if (ch === '\x03') { // ctrl-C
write('^C\n');
process.exit(130);
}
else if (ch === '\x15') { // ctrl-U
clearLine();
length = 0;
}
else if (key.name === 'enter' || key.name === 'return') {
write('\n');
process.stdin.off('keypress', callback);
resolve(buffer.substr(0, length).trim());
}
else if (key.name === 'backspace' || key.name === 'left') {
if (length > 0) {
write('\x08 \x08');
--length;
}
}
else if (key.name === 'delete') {
if (length > 0) {
write('\x08 \x08');
buffer = buffer.substr(0, --length) + buffer.substr(length + 1);
}
}
else if (key.name === 'up') {
clearLine();
write('\n');
process.stdin.off('keypress', callback);
resolve('\x18');
}
else if (key.name === 'right') {
if (length < buffer.length) {
write(buffer.charAt(length++));
}
}
else if (ch != null && ch >= ' ' && !key.ctrl && !key.meta) {
write(ch);
buffer = buffer.substr(0, length) + ch + buffer.substr(length++);
}
};
process.stdin.on('keypress', callback);
});
}
I am completely new to javascript and haven't learned any kind of basics. However, I did learn to do some codes.
I have made a leveling bot that will send the users exp points for their message once per 40 seconds. But the command which they will check their level stats with is an embed that has gotten into that time. Now users have to wait for like 40 seconds to activate that command or even if they haven't, if they have typed something over 40 seconds ago, they can't activate the command unless another 40 seconds have passed.
if (message.guild.id in stats === false) {
stats[message.guild.id] = {};
}
const guildStats = stats[message.guild.id];
if (message.author.id in guildStats === false) {
guildStats[message.author.id] = {
xp: 0,
level: 0,
last_message: 0,
};
}
const userStats = guildStats[message.author.id];
userStats.xp += random1.int(80, 100);
if (Date.now() - userStats.last_message > 40000) {
userStats.last_message = Date.now();
const rankS = '745901272506302484';
const rankA = '744810702845378680';
const rankB = '744835558991200367';
const rankC = '750739926286336081';
const rankD = '744810818771615745';
const rankE = '744810822982959106';
const rankF = '744810963558989844';
const xpToNextLevel =
5 * Math.pow(userStats.level, 1) + 100 * userStats.level + 100;
if (userStats.xp >= xpToNextLevel) {
userStats.level++;
if (userStats.level >= 35) {
message.member.roles.add(rankS);
}
if (userStats.level >= 25) {
message.member.roles.add(rankA);
}
if (userStats.level >= 15) {
message.member.roles.add(rankB);
}
if (userStats.level >= 10) {
message.member.roles.add(rankC);
}
if (userStats.level >= 7) {
message.member.roles.add(rankD);
}
if (userStats.level >= 5) {
message.member.roles.add(rankE);
}
if (userStats.level >= 1) {
message.member.roles.add(rankF);
}
const Embed5 = new Discord.MessageEmbed()
.setAuthor(
message.author.username + '🎖️' + userStats.level,
message.author.displayAvatarURL()
)
.setDescription('You just leveled up to ' + userStats.level)
.addField(
'Keep up the work',
'Text/VC/Post stuff in the server to gain more XP.'
)
.setColor(0xff5733)
.setFooter('Type Ahri level to check you level card.');
userStats.xp = userStats.xp - xpToNextLevel;
client.channels.cache.get('743135573530902701').send(Embed5);
}
const args1 = message.content.slice(prefix.length).split(' ');
const command1 = args1.shift().toLowerCase();
if (command1 === 'level') {
const Embed6 = new Discord.MessageEmbed()
.setAuthor(
'Level card for ' + message.author.username,
message.author.displayAvatarURL()
)
.addField('Current level ', userStats.level, true)
.addField('Current exp ', userStats.xp, true)
.addField('Exp needed for next level ', xpToNextLevel)
.setColor(0xff5733);
userStats.xp = userStats.xp - xpToNextLevel;
client.channels.cache.get('743135573530902701').send(Embed6);
jsonfile.writeFileSync('stats.json', stats);
console.log(message.author.username + ' now has ' + userStats.xp);
console.log(xpToNextLevel + ' XP needed for next level.');
}
}
The main problem is I have to pull that (Embed6) out from this 2 brackets from the end. But I can't. One I pull it out, it can't connects it's objects to the consts that are inside the brackets.
Hi I'm struggling to get the hang of JavaScript and am practicing by trying to write a coin toss game using conditional statements and functions can someone point out where I'm going wrong?
var coinToss = prompt("heads or tails?");
console.log(coinToss);
var headTails = function() {
var outCome = Math.floor(Math.random() * 2) + 1;
if (outCome === 1) {
outCome = "heads";
} else {
outCome = "tails";
}
};
console.log(outCome);
var compare = function(outCome, coinToss) {
if (outCome === coinToss.toLowerCase) {
document.write("<p>You Win!</p>");
} else {
document.write("<p>You Loss!</p>")
};
};
toLowerCase is a method hence toLowerCase()
Call the function as compare(headTails(), coinToss);
Return the value from function headTails
Ternary could be used instead of if-else
var coinToss = prompt("heads or tails?");
var headTails = function() {
var outCome = Math.floor(Math.random() * 2) + 1;
console.log(outCome === 1 ? "heads" : "tails");
return outCome === 1 ? "heads" : "tails";
};
var compare = function(outCome, coinToss) {
if (outCome === coinToss.toLowerCase()) {
document.write("<p>You Win!</p>");
} else {
document.write("<p>You Loss!</p>")
};
};
compare(headTails(), coinToss);
You need to call the compare function, like so:
compare(headsTails(),coinToss);
I have JavaScript calculator wherein I have defined two arrays as follows:
var degInc, degArr = [];
var radInc, radArr = [];
var PI = Math.PI;
var radStart = (-91*PI/2), radEnd = (91*PI/2);
for (degInc = -8190; degInc <= 8190; degInc+=180) {
degArr.push(degInc);
}
for (radInc = radStart; radInc <= radEnd; radInc+=PI) {
var radIncFixed = radInc.toFixed(8);
radArr.push(radIncFixed);
}
to be used in conjunction with the tangent function (below) so as to display a value of Undefined in an input (HTML below) should the user attempt to take the tangent of these values (I have included other relavent function as well):
Input -
<INPUT NAME="display" ID="disp" VALUE="0" SIZE="28" MAXLENGTH="25"/>
Functions -
function tan(form) {
form.display.value = trigPrecision(Math.tan(form.display.value));
}
function tanDeg(form) {
form.display.value = trigPrecision(Math.tan(radians(form)));
}
function radians(form) {
return form.display.value * Math.PI / 180;
}
with jQuery -
$("#button-tan").click(function(){
if (checkNum(this.form.display.value)) {
if($("#button-mode").val() === 'DEG'){
tan(this.form); // INSERT OTHER 'if' STATEMENT HERE FOR RAD ARRAY
}
else{
tanDeg(this.form); // INSERT OTHER 'if' STATEMENT HERE FOR DEG ARRAY
}
}
});
I would like to incorporate an array check within the .click function such that if the user input is contained in the array (degArr or radArr depending on the mode), the calculator returns Undefined. Now, I know how to display Undefined in the input display ($('#disp').val('Undefined')), but I cannot figure out how to configure an if statement that checks the relevant array. Is there a way to do so within the #button-tan function where I have commented?
Loop through the arrays on click and set a variable if you find a matched value.
You can do something like this:
$("#button-tan").click(function(e) {
e.preventDefault();
var userInput = $('#disp').val();
var buttonMode = $('#button-mode').val();
var displayVal = '';
if (buttonMode === 'DEG') {
var radFound = false;
radArr.forEach(function(item) { // changed from degArr
if (item === userInput) {
radFound = true;
}
if (radFound) {
displayVal = 'undefined';
} else {
tan(this.form);
}
});
} else {
var degFound = false;
degArr.forEach(function(item) {
if (item === userInput) {
degFound = true;
}
if (degFound) {
displayVal = 'undefined';
} else {
tanDeg(this.form);
}
});
}
});
You could create a simple object of a Calculator class, which keeps a reference to these arrays, and use like this. I changed some methods to receive the input as parameter rather than form.
$(function () {
function Calculator()
{
var degInc;
this.degArr = [];
var radInc;
this.radArr = [];
var PI = Math.PI;
var radStart = (-91*PI/2);
var radEnd = (91*PI/2);
for (degInc = -8190; degInc <= 8190; degInc+=180) {
this.degArr.push(degInc);
}
for (radInc = radStart; radInc <= radEnd; radInc+=PI) {
var radIncFixed = radInc.toFixed(8);
this.radArr.push(radIncFixed);
}
}
var calc = new Calculator();
function tan(input) {
alert("tan called");
var value = Math.tan(input.value);
alert("tan called. value: " + value);
input.value = value;
}
function tanDeg(input) {
alert("tanDeg called");
var value = Math.tan(radians(input));
alert("tanDeg called. value: " + value);
input.value = value;
}
function radians(input) {
alert("radians called");
var value = input.value * Math.PI / 180;
alert("radians called. value: " + value);
return value;
}
$("#button-tan").click(function(){
alert (calc.degArr);
alert (calc.radArr);
var displayInput = $("#disp");
alert("user input: " + displayInput.val());
if (!isNaN(displayInput.val()))
{
if($("#button-mode").val() === 'DEG')
{
if (calc.radArr.indexOf(displayInput.val()) > -1)
{
alert("user input is in radArr");
}
else
{
alert("user input IS NOT in radArr");
tan(displayInput);
}
}
else
{
if (calc.degArr.indexOf(displayInput.val()) > -1)
{
alert("user input is in degArr");
}
else {
alert("user input IS NOT in degArr");
tan(displayInput);
}
}
}
else
alert("Not a number in input");
});
});
If you wanna do some tests, I created a JSFiddle demo here. Type -8190 in the first input, then click the button. It's gonna be inside the array. Then try typing "DEG" in the second input and clicking again, you'll notice code will check against another array (due to IFs). I couldn't make your auxiliar functions to calculate a value, but I think this helps you with your initial problem.
indexOf should work...
$("#button-tan").click(function(){
if (checkNum(this.form.display.value)) {
if($("#button-mode").val() === 'DEG'){
if (radArr.indexOf(Number(this.form)) > -1) {
$('#disp').val('Undefined');
} else {
tan(this.form);
}
}
else{
if (degArr.indexOf(Number(this.form)) > -1) {
$('#disp').val('Undefined');
} else {
tanDeg(this.form);
}
}
}
});