I'm just writing a very simple function in javascript to calculate a factorial. I understand that in javascript you can assign a function to a variable.
So I have tried this on an online compiler (https://repl.it/languages/javascript) and this is what my code looks like
var mynum = prompt("Enter a number", "<enter a number>");
var answer;
if (isNaN(mynum)){
console.log(mynum +" is not a number");
}
else{
console.log("You entered "+mynum);
answer = function (mynum){
var i = mynum-1;
var temp = mynum;
while(i>0){
temp = temp*i;
i--;
}
return temp;
};
console.log("the factorial of "+mynum+" is "+answer);
}
But when I run this the output keeps including the whole function as "answer"
You entered 23
the factorial of 23 is function (mynum) {var _loopStart = Date.now(),_loopIt = 0;
var i = mynum - 1;
var temp = mynum;setTimeout(function () {_loopStart = Infinity;});
while (i > 0) {if (++_loopIt > 5000 && Date.now() - _loopStart > 150) throw new RangeError("Potential infinite loop. You can disable this from settings.");
temp = temp * i;
i--;
}
return temp;
}
However i don't have this issue when i create the function and then call it separately (something like answer = function(mynum).
Can anyone please let me know why this is happening?
Thanks!
Assigning a function to a variable is different from assigning its evaluation.
In your case, you have two solutions available :
Make an effective call to your assigned function at logging time:
console.log("the factorial of "+mynum+" is "+answer(mynum));
Make an effective call to your assigned function at assignation time:
answer = (function (mynum){
var i = mynum-1;
var temp = mynum;
while(i > 0) {
temp = temp*i;
i--;
}
return temp;
}(mynum));
Both solutions are quite equivalent for your specific situation.
Why?
Because declaring a function like so:
var func = function () {
console.log("Hello!");
};
Or like so:
function func () {
console.log("Hello!");
};
Has little difference
As pointed out, you have to call it as a function.
var mynum = prompt("Enter a number", "<enter a number>");
var answer;
if (isNaN(mynum)){
console.log(mynum +" is not a number");
}
else{
console.log("You entered "+mynum);
answer = function (mynum){
var i = mynum-1;
var temp = mynum;
while(i>0){
temp = temp*i;
i--;
}
return temp;
};
console.log("the factorial of "+mynum+" is "+answer (mynum));
}
Alternatively, you could use IIEF(mmediately invoked function expression):
var mynum = prompt("Enter a number", "<enter a number>");
var answer;
if (isNaN(mynum)){
console.log(mynum +" is not a number");
}
else{
console.log("You entered "+mynum);
answer = (function (mynum){
var i = mynum-1;
var temp = mynum;
while(i>0){
temp = temp*i;
i--;
}
return temp;
})(mynum);
console.log("the factorial of "+mynum+" is "+answer);
}
Note that I've added a parenthesis around your function and passed in arguments. That's how you can immediately invoke functions.
When you return a function in javascript such as answer(). You must call it as such.
console.log("the factorial of "+mynum+" is "+answer(mynum));
You need to use the function that you wrote by calling it i.e
function add (a,b) {
return a + b;
}
add(1,2);
Related
I have two javascript closures and I'm trying to understand why one will accept and input with a particular syntax and the other will reject.
function multiply(factor) {
var ace = (function(number) {
return number*factor;
});
return ace;
}
var yup = multiply(4);
console.log(yup(5));
This outputs 20 to the console as it should.
The second Closure I have is
var k = 3;
var add = (function () {
console.log(k);
var counter = k;
return function (j) {counter += 1; return counter*j}
})(k);
add();
console.log(add(5));
The output is 20 as it should be.
This issue I'm having that if I try to use the syntax of
(function() {
})(number);
In the first closure it does not work and outputs "number is not defined"
And if I try to input into the second closure
(function (k) {
var counter = k;
return function (j) {counter += 1; return counter*j}
});
I get out
function (j) {counter += 1; return counter*j}
to the console.
My question is, what am I not understanding about closers the () at the end of them.
The difference is whether you are creating the closure right away through an IIFE, or a function that makes the closure when called.
Your first snippet written in the second style would be
var yup = (function multiply(factor) {
return function ace(number) {
return number*factor;
};
})(4); // the multiply(4) call is inlined into the statement with the definition
console.log(yup(5));
Your second snippet written in the first style would be
function makeAdd(k) {
console.log(k);
var counter = k;
return function (j) {
counter += 1;
return counter*j;
}
}
var add = makeAdd(3);
add();
console.log(add(5));
I have 3 messages in variables.
var msg1 = "hello1";
var msg2 = "hello2";
var msg3 = "hello3";
I am trying to create a function that when i click it the first time it console.log(msg1), when i click it the second time it console.log(msg2), 3rd time console.log(msg3), 4th time console.log(msg1) and 5th msg2 etc.
$scope.clickMsg = function () {
console.log(msg1);
}
i've tried loops, timers etc but i could not make it work.
Does anyone know how to do this?
Use an array instead, and it's a bit easier, you'd just increment a number on each click, and use that number to select the item from the array
var msg = [
"hello1",
"hello2",
"hello3"
];
var i = 0;
var $scope = {};
$scope.clickMsg = function () {
console.log( msg[i] );
i++; // increment
if (i === msg.length) i = 0; // reset when end is reached
}
document.getElementById('test').addEventListener('click', $scope.clickMsg)
<button id="test">Click</button>
ES6 Generators based version:
var messages = (function*() {
for(;;) { yield msg1; yield msg2; yield msg3; }
})()
$scope.clickMsg = function () {
console.log(messages.next().value);
}
Unlike other answers, does not require you to use a different datatype and will also work for the locally scoped variables (i.e. non-window scoped variables).
Try It Online !
There are a few ways to do this in terms of accessing the string, I'd recommend putting them into an array rather than accessing the global/scoped object but it's up to you. Anyway on to the code.
var messagesArray = ["hello1", "hello2", "hello3"];
var messagesObject = {
msg1: "hello1",
msg2: "hello2",
msg3: "hello3"
}
var counter = 0;
function LogMessage() {
console.log(messagesArray[counter % 3]);
console.log(messagesObject["msg" + (counter % 3 + 1)]);
counter++
}
<button onclick="LogMessage()">Click Me</button>
Simply use with increment value like this
var msg1 = "hello1";
var msg2 = "hello2";
var msg3 = "hello3";
var c = 1;
$scope.clickMsg = function () {
c = c > 3 ? 1 : c;
console.log(window['msg'+c])
c++;
}
Working snippet
var msg1 = "hello1";
var msg2 = "hello2";
var msg3 = "hello3";
var c = 1;
var $scope={} //for testing
$scope.clickMsg = function () {
c = c > 3 ? 1 : c;
console.log(window['msg'+c])
c++;
}
function check(){ //for testing
$scope.clickMsg();
}
<button onclick="check()">click</button>
The alternative is using scopes, defining them as
this["msg"+i] = "some stuff";
and retrieving them as
this.msg0;
just do something like this, will work for you, make sure you reset it back if needed or do something, otherwise after first loop, you get undefined:
var msgs = ["hello1","hello2","hello3"], i=0;
$scope.clickMsg = function() { //angular $scope for example
console.log(msgs[i]);
if(i < msgs.length-1) {
i++;
} else {
i=0; //reset the loop
}
}
For some reason I get an error when I give the function a name..
However if I make it an anonymous function and assign it to a variable then I can call the function.
function test(){
console.log(this)
}
test();
//**************
// recursion 1
//**************
var recursion = function(n){
if(n==0){
// console.log('yup');
return 'success';
}
// console.log(n)
return recursion(n - 1);
}
var x = recursion(10);
// console.log(x);
//**************
// recursion 2
//**************
var countDownFrom = function(x){
if(x === 0){
return true;
}
// console.log(x)
return countDownFrom(x-1)
}
// console.log(countDownFrom(10))
//**************
// fibonacci
//**************
// console.time('fib')
function fibonacci(){
var a = 0,
b = 1,
result = b;
for(var i =0; i<100; i++){
console.log(result);
result = a + b;
a=b;
b=result;
}
}
// console.log(fibonacci())
// console.timeEnd('fib')
//**************
// removeDuplicate
//**************
console.time('dups')
function removeDuplicate(arr){
var exists ={},
outArr = [],
elm;
for(var i =0; i<arr.length; i++){
elm = arr[i];
if(!exists[elm]){
console.log(exists);
outArr.push(elm);
exists[elm] = true;
console.log(exists);
console.log(outArr);
console.log(elm);
}
}
return outArr;
}
removeDuplicate([1,3,3,3,1,5,6,7,8,1]);
console.timeEnd('dups')
//**************
// mergeSorting
//**************
function mergeSortedArray(a, b){
var merged = [],
aElm = a[0],
bElm = b[0],
i = 1,
j = 1;
if(a.length ==0)
return b;
if(b.length ==0)
return a;
/*
if aElm or bElm exists we will insert to merged array
(will go inside while loop)
to insert: aElm exists and bElm doesn't exists
or both exists and aElm < bElm
this is the critical part of the example
*/
while(aElm || bElm){
if((aElm && !bElm) || aElm < bElm){
merged.push(aElm);
aElm = a[i++];
}
else {
merged.push(bElm);
bElm = b[j++];
}
}
return merged;
}
//**************
// swap number without temp
//**************
function swapNumb(a, b){
console.log('before swap: ','a: ', a, 'b: ', b);
b = b -a;
a = a+ b;
b = a-b;
console.log('after swap: ','a: ', a, 'b: ', b);
}
swapNumb(2, 3);
//**************
// JS reverse string
//**************
function reverseString(str) {
var newString = "",
stringLength = str.length;
for (var i = stringLength - 1; i >= 0; i--) {
newString += str[i];
}
return newString;
}
var newString = reverseString('hello');
console.log(newString);
var test = "yoyo";
console.log(test += 'asdfa')
//**************
// JS Reverse Word
//**************
function reverseWords(str){
var rev = [],
wordLen = 0;
for(var i = str.length-1; i>=0; i--){
if(str[i]==' ' || i==0){
rev.push(str.substr(i,wordLen+1));
wordLen = 0;
}
else
wordLen++;
}
return rev.join(' ');
}
var str = "lets go all day";
console.log(str.substr(11,5))
var s = reverseWords(str);
console.log(s);
//**************
// JS Palindrome
//**************
function isPalindrome(str){
var i, len = str.length;
for(i =0; i<len/2; i++){
if (str[i]!== str[len -1 -i])
return false;
}
return true;
}
isPalindrome('madam');
isPalindrome('toyota');
//**************
// JS this
//**************
function test(){
console.log(this)
}
test();
This might be a hoisting issue. If you have more JS code above your code snippet, test might have been assigned to something else.
This will cause a TypeError because test will be a string by the time you call it:
// ... some code
var test = 'This is a test.';
// ... more code
function test() {
console.log(this);
}
test();
This will work because test is assigned to a function right before you call it:
// ... some code
var test = 'This is a test.';
// ... more code
test = function () {
console.log(this);
}
test();
In the first example, this is what the interpreter does, more or less:
Assign a function definition to test. (This happens first because it hoists function declarations above everything else)
Reassign test to be a string.
Invoke test, which is a string.
Second example:
Declare test with no value (undefined).
Assign test to a string.
Reassign test to a function.
Invoke test, which is a function.
I just did a CTRL+F on your code and it seems that you already have a variable defined with the name of test in above scope. Please edit your code to remove the test variable declared above
It looks OK, the function prints an object when you call this inside the function
function test() {
console.log(this)
}
test()
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.
(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();