Is this a scope issue or how function creation issue? - javascript

I haven't done Javascript in years and I'm trying to get back into it. I just wanted to create a couple random numbers and add them together. I also wanted to practice using "getVariable()" to protect manipulation of the original variable while making them accessible to the entire script. I must be remembering this wrong or I'm doing something really stupid. I keeping getting a message that getScore1 is undefined. I tried writing it as function getScore1() and this.getScore1 = function(){}. Can someone please point me in the correct direction?
function twoRandomScores(){
var score1 = Math.random(1, 10);
var score2 = Math.random(1, 10);
return score1 + score2;
this.getScore1 = function(){
return this.score1;
}
function getScore2(){
return this.score2;
}
}
document.write(getScore1() + '+' + getScore2() + '=' + twoRandomScores());

The getScore functions are defined inside your twoRandomScores() function so they won't simply be accessible from outside of it. The code as you've written it now doesn't really make sense either because the getScore() functions would only have any meaning after twoRandomScores() was called (and for one particular call of it). Here's one way you could approach this problem:
function twoRandomScores(){
var score1 = Math.random(1, 10);
var score2 = Math.random(1, 10);
return {
score: score1 + score2,
getScore1: function(){
return score1;
},
getScore2: function(){
return score2;
}
};
}
var scores = twoRandomScores();
console.log(scores.getScore1() + '+' +
scores.getScore2() + '=' +
scores.score);
Then again, having two functions for getScore1, getScore2 doesn't really accomplish anything, so you could just do:
function twoRandomScores(){
var score1 = Math.random(1, 10);
var score2 = Math.random(1, 10);
return {
score: score1 + score2,
score1: score1,
score2: score2
};
}
var scores = twoRandomScores();
console.log(scores.score1 + '+' + scores.score2 + '=' + scores.score);

Sure that your code is correct? Before assigning getScore1, you are returning out of the function, so the assignment to getScore1 and getScore2 never occurs. Hence the undefined error...

You're mixing up a regular function with the type of function used to create an object. This is how it might work if you wanted to make an object (JSFiddle)
function RandomScore() {
var score1 = Math.random() * 10,
score2 = Math.random() * 10;
// make functions which are properties of the new object
this.sum = function() {
return score1 + score2;
}
this.getScore1 = function() {
return score1;
}
this.getScore2 = function() {
return score2;
}
}
var randomScore = new RandomScore();
console.log(randomScore.getScore1() + '+' + randomScore.getScore2() + '=' + randomScore.sum());
The following would also work without making an object, although it would be rather unusual in practice (JSFiddle):
var getScore1, getScore2, sum; // define variables with global scope
function randomScore() {
var score1 = Math.random() * 10,
score2 = Math.random() * 10;
getScore1 = function() {
return score1;
}
getScore2 = function() {
return score2;
}
return score1 + score2;
}
// we need to run the function once before
// getScore1 and getScore2 will have any functions assigned to them
sum = randomScore();
// now we can access getScore1 and getScore2 outside of our randomScore function
console.log(getScore1() + '+' + getScore2() + '=' + sum);

Related

Javascript OOM error

New to JS here, so I apologize if I'm missing something obvious. Trying to build a random number generator (it works in a nested manner, so something like a list of tuples of random number), but I get a OOM error with this code. (Say, if i try to do something like generateList(6))
function generateList(num){
var arr = [];
for(i=0;i<num;i++){
arr.push(generateTuple());
}
return arr;
}
function generateTuple(){
var tuple = [];
for(i=0;i<3;i++){
tuple.push(Math.floor(Math.random() * 300));
}
return '(' + tuple[0] + ',' + tuple[1] + ',' + tuple[2] + ')';
}
OTOH, if I just generate the random numbers individually and return them (instead of using a list), it works without errors. Can anyone enlighten me as to what is going on here?
function generateTuple(){
var a = Math.floor(Math.random() * 300);
var b = Math.floor(Math.random() * 300);
var c = Math.floor(Math.random() * 300);
return '(' + a + ',' + b + ',' + c + ')';
}
EDIT: So basically if you run the code, it gets stuck in some loop, and after a period of time in the console it returns the OOM error. So I assume it's some memory overflow or something somewhere.
You are creating global i by declaring it without var or let, then you loop with it. That creates unprecedented values for i, leading to the loop will never complete. Declare your variables correctly.
for(var i=0;i<num;i++) // better: let i = 0; ...
and
for(var i=0;i<3;i++) // better: let i = 0; ...
Your is are global variables. Always declare variables with const or let (or var) to avoid global pollution and unexpected behavior (like what's happening here).
Each time generateTuple is run, i gets set to 3 at the end of the for loop in generateTuple. So, the i referenced by generateList - which references the same global variable - never has a chance to get any higher than 4. So if you call generateList with higher numbers, you'll get an infinite loop.
Just declare your variables properly:
function generateList(num){
var arr = [];
for(let i=0;i<num;i++){
arr.push(generateTuple());
}
return arr;
}
function generateTuple(){
var tuple = [];
for(let i=0;i<3;i++){
tuple.push(Math.floor(Math.random() * 300));
}
return '(' + tuple[0] + ',' + tuple[1] + ',' + tuple[2] + ')';
}
console.log(generateList(10));

Having Trouble Understanding Javascript Methods

This is my current assignment :
Add a method that will increase the value of one of the numeric properties.
Add a method that will decrease the value of the same numeric property.
Create a for loop after creating an instance of the character. The loop will iterate 100 times.
Inside the loop call one of the methods based on a random number from zero to 3. Using a switch statement, if the value is 0 then call the method that losses; 1 don’t call anything; 2 call the method that gains.
Here is my current coding. I know I'm doing something wrong. I just can't figure out what I am doing wrong with the switch statement.
var BR = "<br />";
function person(name, sandwiches) {
this.name = name;
this.sandwiches = sandwiches;
function jump() {
var text = " leaps over an obstacle.";
return fname + text;
}
function run() {
var text = " runs as fast as they can";
return fname + text;
}
function dodge() {
var attack = math.random();
var att = math.round(attack);
var defense = math.random();
var def = math.round(defense);
if(att > def) {
return "You missed";
}
else {
return "You dodged";
}
}
function date() {
var today = new Date();
return today.toDateString();
}
function shout() {
var word = "Oh no";
return word.toUpperCase();
}
this.addSandwich = function (sandwiches) {
sandwiches = sandwiches + 1;
return sandwiches;
};
this.loseSandwich = function (sandwiches) {
sandwiches = sandwiches - 1;
return sandwiches;
};
}
var character = new person("Jerry", 1);
for(i=0; i < 100; i++) {
var random = Math.floor(Math.random() * 3);
switch(random) {
case 0:
character.loseSandwich(character.sandwiches);
console.log(sandwiches);
break;
case 1:
break;
case 2:
character.addSandwich(character.sandwiches);
break;
}
}
document.write("Name: " + character.name + BR);
document.write("Sandwiches: " + character.sandwiches + BR);
Math.floor(Math.random() * 3) is not what you want.
You want something like Math.random() % 3 to get 0, 1, or 2 every single time
Not sure if this is your problem, but it is at least one of them;
In a few places you have a lowercase math, for example:
function dodge() {
var attack = math.random();
JavaScript is case-sensitive, and it should be Math.random() not math.random()
Another issue is that these functions:
this.addSandwich = function (sandwiches) {
sandwiches = sandwiches + 1;
return sandwiches;
};
do not change the number of sandwiches. You get in a value of sandwiches, add or subtract 1, then return that changed number, but never use the returned result.
You are only changing the value of the variable that was passed in, not changing the number of sandwiches on the instance of the person.
Note that this.sandwiches (the variable on the instance of a person) is not the same variable as sandwiches (the function argument)
I dont think there is any reason to pass the number of sandwiches into those functions, and they could just do:
this.addSandwich = function () {
this.sandwiches = this.sandwiches + 1;
};
or more simply:
this.addSandwich = function () {
this.sandwiches++;
};
Another problem here:
character.loseSandwich(character.sandwiches);
console.log(sandwiches);
The console.log statement is trying to log sandwiches but that is not a variable at that point. You probably wanted console.log(character.sandwiches); However this wouldn't cause an exception, it would just always log undefined.

Javascript - how to detect how many functions are being called? (multiple parentheses)

Let me propose an example that works, then follow up with what fails, highlighting the point to my question.
Here, we have 3 functions being called (1 named, 2 anonymous):
var add = function(a, b) {return a+b};
var multiply = function(a, b) {return a*b};
function myFunction(fxn) {
return function(x) {
return function(y) {
return fxn(x,y);
}
}
}
myFunction(add)(2)(3)
Understandably, this call fails:
myFunction(add)(2)(3)(4)
How would I detect how many functions are being called? In the 2nd call, I'm calling 4 functions (1 named, 3 anonymous).
How would I rewrite the myFunction function in a way that compensated for any given amount of calls? I know we can detect how many arguments a function was given, but is there a way to detect how many functions are being called? I hope I worded this correctly. Thanks.
To find out if a variable contains a reference to a function you can use below code:
if (typeof(v) === "function") alert("This is a function")
Based on above you can find out on how many nested functions there are
function myFunction() {
return function() {
return function() {
return 1 + 2;
}
}
}
var count = 0;
var v = myFunction();
while (typeof(v) === "function") {
count++;
v = v();
}
alert("Nr of nested functions: " + count)
Even if this has no practical use case I can think of, this is a possible solution:
var add = function(a, b) {
return a + b
};
var multiply = function(a, b) {
return a * b
};
var counter = 0;
var result = 0;
function myFunction(fxn) {
counter = 1;
result = 0;
return function first(x) {
++counter;
return function second(y) {
++counter;
x = result ? result : x;
result = fxn(x, y);
return second;
}
}
}
myFunction(add)(1)(2)(3)(4);
alert('Result is: ' + result + '; Parentheses count: ' + counter);

Javascript: How to get the value of a function?

I am making a quick game where a player damages a enemy npc. I have a function below that does the calculation for the damage, but I can't get the console log to say i'm doing "X" amount of damage. What am I doing wrong? Instead, it just pulls up the function statement, but I want it to give me the functions value!
var damage = function() {
return Math.floor(Math.random() * 5 + 1);
};
I'm calling my function in another code properly, but when I try to console log the damage in that other code, I get a error.
function attackButton() {
darkwarrior.hp = darkwarrior.hp - damage();
console.log(darkwarrior.hp);
console.log(damage);
If you run console.log(damage()); you will get the "X" amount of damage instead of the function statement. So you could change attackButton() function to be:
function attackButton() {
var damageDealt = damage();
darkwarrior.hp = darkwarrior.hp - damageDealt;
console.log(darkwarrior.hp);
console.log(damageDealt);
I'm not sure to understand, you want to log the result? If so, you can do that:
var damage = function() {
return Math.floor(Math.random() * 5 + 1);
};
console.log(damage());
EDIT:
you forgot the (). + the value will not be the same if you don't put it in a variable:
function attackButton() {
var amount = damage()
darkwarrior.hp = darkwarrior.hp - amount;
console.log(darkwarrior.hp);
console.log(amount);
}
you just have to use an expression to assign the value to a variable. Then log it. Then return it.
var damage = function() {
var num = Math.floor(Math.random() * 5 + 1);
console.log(num);
return num;
};
damage();
Something like this should work for you.
function NPC(startingLife, name) {
this.hp = startingLife;
this.name = name
}
NPC.prototype.takeDamage = function(amount) {
this.hp = Math.max(this.hp - amount, 0);
if (this.hp == 0) {
console.log(this.name + " Dies");
}
return this.hp;
};
function damage() {
return Math.floor(Math.random() * 5 + 1);
}
var darkwarrior = new NPC(4, 'Dark Warrior');
function attackButton() {
var amount = damage();
darkwarrior.takeDamage(amount);
console.log("Dark Warrior took " + amount + " points of damage");
}
document.querySelector('#attack-button').addEventListener("click", attackButton);
<button id="attack-button">ATTACK!</button>
You are just returning the value instead of printing it. You should instead replace return with console.log(

JavaScript: returning NaN (Part 2)

(note this is similar to but not the same as the question I asked moments ago - the solution to that question was to add the brackets when calling Math.Random)
At the bottom of the code below, I'm dealing out two hands of blackjack myhand and yourhand and then logging the hands to the console
"I scored a "+myHand.score()+" and you scored a "+ yourHand.score());
However, the result I'm getting is
I scored NaN and you scored a NaN
Originally, the getValue method in the Card constructor was passed a parameter called card but the instructions for building the Hand constructor said to call getValue without passing a parameter
this.card1.getValue();
so I changed the getValue method to take the var number (which is in the Card constructor)
anyways, to make a long story short, whatever i do, it's printing out
I scored NaN and you scored a NaN
and I'm not sure exactly where I'm going wrong.
// Make your card constructor again here, but make sure to use private
// variables!
function Card(num, suit){
var number = num;
var suits = suit;
this.getSuit = function(){
return suits;
};
this.getNumber = function(){
return number;
};
this.getValue = function(number){
if (number > 10){
return 10;
}else if (number === 1){
return 11;
}else{
return number;
}
};
}
function Hand(){
this.card1 = deal();
this.card2 = deal();
this.score = function(){
var score1 = this.card1.getValue();
var score2 = this.card2.getValue();
return score1 + score2;
};
}
// Make a deal function here. It should return a new card with a suit
// that is a random number from 1 to 4, and a number that is a random
// number between 1 and 13
var deal = function(){
var suit = Math.floor(Math.random() * 4 + 1);
var number = Math.floor(Math.random() * 13 + 1);
return new Card(number, suit);
};
// examples of the deal function in action
var myHand = new Hand();
var yourHand = new Hand();
console.log("I scored a "+myHand.score()+" and you scored a "+ yourHand.score());
Your getValue function is wrong. It should be:
this.getValue = function() {
if( this.number>10) return 10;
if( this.number==1) return 11;
return this.number;
}
A hint that something was wrong is that you are calling this.card1.getValue() with no arguments, whereas you defined this.getValue(number) with an argument.
When you address card.getValue() it requires some input
this.getValue = function(number){
if (number > 10){
return 10;
}else if (number === 1){
return 11;
}else{
return number;
}
};
The function doest not return anything, resulting in a NaN.
To solve this, use this.number instead
Your get value function accepts a number argument
this.getValue = function(number)
But you aren't passing in the value here:
var score1 = this.card1.getValue();
var score2 = this.card2.getValue();

Categories