Javascript object members - javascript

var math = {
Factorial:function(n) {
if (n == 0) {
return 1;
}
return n * Factorial(n - 1);
},
CalculateFactorial:function() {
var myValue = document.getElementById('myTextBox').value;
if (myValue.length == 0) {
alert("Please input the correct value!");
return;
}
var result = Factorial(myValue);
document.getElementById('title').innerHTML = result;
}
}
Hello guys. New to JavaScript and testing different things, coming from C# language things are pretty the same yet different.
I am trying to do something and no success.
Having the script above attached to a simple html button , trying to call the CalculateFactorial , math.CalculateFactorial(); , but what is wierd is that CalculateFactorial() doesn't actually see the Factorial() method. But in the math object I can see both methods. Wierd.
"JavaScript runtime error: 'Factorial' is undefined"

A good practice in JavaScript is to name all of your functions even if you assign them to a variable or use them like object's property. In your case just give a name to your Factorial function like this:
Factorial:function factorial(n)
{
if (n == 0)
{
return 1;
}
return n * factorial(n - 1);
},
For the problem of not seeing Factorial in your CalculateFactorial function just use this.Factorial when you invoke it.

This should fix the issue... if you want Factorial to be an internal only function (just a utility for the exposed CalculateFactorial) then you can do so this way:
var math = new function() {
var $this = this;
var Factorial = function(n) {
if (n == 0) {
return 1;
}
return n * Factorial(n - 1);
}
$this.CalculateFactorial = function() {
var myValue = document.getElementById('myTextBox').value;
if (myValue.length == 0) {
alert("Please input the correct value!");
return;
}
var result = Factorial(myValue);
document.getElementById('title').innerHTML = result;
}
}
The deeper design issue here is this is not particularly reusable javascript. You should consider pulling CalculateFactorial() out of the math object and into it's own handler... probably a click handler would be my guess like this:
var math = new function() {
var $this = this;
$this.Factorial = function(n) {
if (n == 0) {
return 1;
}
return n * $this.Factorial(n - 1);
}
}
$("#calcButton").click(function() {
var myValue = document.getElementById('myTextBox').value;
if (myValue.length == 0) {
alert("Please input the correct value!");
return;
}
var result = math.Factorial(myValue);
document.getElementById('title').innerHTML = result;
})

That happens beceause the Factorial method is part of the math object, and it doesn't reside in the global scope. When you try to call it directly, the parser will try to find that method into the global scope, and then, it will thrown an ReferenceError.
Since you're using the method inside the object itself, you can use the this keyword, because it will look into the object's context and find the method Factorial.
Another way of calling the Factorial method is by using the object, e.g: math.Factorial.
Take a look at the example below:
var math = {
Factorial: function(n) {
return n === 0 ? 1 : n * this.Factorial(n - 1);
},
CalculateFactorial: function(txt) {
document.getElementById('title').innerHTML = this.Factorial(txt.value);
}
};
document.getElementById('myTextBox').addEventListener('input', function() { math.CalculateFactorial(this); });
<input type="text" id="myTextBox" placeholder="Fatorial">
<div id="title"></div>

Related

Function worked, now RangeError

Why am I getting a RangeError: Maximum call stack exceeded error? I am trying to parse through text to find math and solve it. It was working until I started to implement parenthesis'. I have tried to find the error but I just can't figure it out.
My Code:
var alg = {
calc: function(eq, solveFor) {
var out;
var sideOne = eq.substring(0, eq.indexOf('='))
var sideTwo = eq.substring(eq.indexOf('=') + 1)
if (sideOne === solveFor) {
alg.simplify(sideTwo);
}
if (sideTwo === solveFor) {
alg.simplify(sideOne);
}
},
simplify: function(eq) {
str = $.trim(eq);
if (str == undefined) {
console.error('Error: null string')
} else {
var charMatch = /^[\d\*\/\+\-\^\(\) ]+$/
if (charMatch.exec(str) === null) {
console.error('Error: Invalid char/expression')
} else {
alg.parMath('not');
alg.expRoot(solve);
alg.multDiv(solve);
alg.addSubtr(solve);
}
}
},
fromPar: function(par) {
alg.parMath(par);
alg.expRoot(solve);
alg.multDiv(solve);
alg.addSubtr(solve);
},
parMath: function(source) {
var reP = /\(([\d\*\/\+\-\^\(\) ]+)\)/
var exP = reP.exec(str)
if (source === 'par') {
str = str.replace(exP[0], solve)
}
if (exP !== null) {
use = 'par'
solve = exP[1]
} else {
use = 'not'
solve = str;
}
},
expRoot: function() {
var fracCon = /(\d+)\/(\d+)/
var reER = /(\d+)(\^)(\d+(\/\d)?)(?!\/)/
var exER = reER.exec(solve)
if (exER !== null) {
var exFC = fracCon.exec(exER[3])
if (exFC !== null) {
var rep = Math.pow(parseFloat(exER[1]),(parseFloat(exFC[1]) / parseFloat(exFC[2])))
} else {
var rep = Math.pow(parseFloat(exER[1]),parseFloat(exER[3]))
}
solve = solve.replace(exER[0], rep)
if (reER.exec(solve) !== null) {
alg.expRoot();
}
}
},
multDiv: function() {
var reMD = /(\d+(?:\.\d+)?) *([\*|\/]) *(\d+(?:\.\d+)?)/
var exMD = reMD.exec(solve);
if (exMD !== null) {
if (exMD[2] === "*") {
var rep = parseFloat(exMD[1]) * parseFloat(exMD[3]);
var rep = Math.round(rep * 1000000) / 1000000;
} else {
var rep = parseFloat(exMD[1]) / parseFloat(exMD[3]);
var rep = Math.round(rep * 1000000) / 1000000;
}
if (use !== 'par') {
solve = solve.replace(exMD[0], rep);
}
if (reMD.exec(solve) !== null) {
alg.multDiv();
}
}
},
addSubtr: function() {
var reAS = /(\d+(?:\.\d+)?) *([\+|\-]) *(\d+(?:\.\d+)?)/
var exAS = reAS.exec(solve); //Getting RangeError here
if (exAS !== null) {
if (exAS[2] === "+") {
var rep = parseFloat(exAS[1]) + parseFloat(exAS[3])
var rep = Math.round(rep * 1000000) / 1000000
} else {
var rep = parseFloat(exAS[1]) - parseFloat(exAS[3])
var rep = Math.round(rep * 1000000) / 1000000
}
if (use !== 'par') {
str = str.replace(exAS[0], rep)
}
if (exAS !== null) {
alg.addSubtr(solve);
} else {
if (use == 'not') {
out = solve;
} else {
alg.fromPar('par')
}
}
} else {
if (use == 'not') {
out = solve;
} else {
alg.fromPar('par')
}
}
}
};
console.log(alg.calc('x=(1+1)', "x"));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
I'm getting the error at the start of addSubtr function (marked by a comment). Can anyone help me find how to fix the error?
The problem is that your code goes into an infinite loop. Here is the relevant part of the logic
addSubtr: function() {
/* ommitted */
var exAS = reAS.exec(solve); //Getting RangeError here
if (exAS !== null) {
/* ommitted - logic here*/
if (exAS !== null) {
alg.addSubtr(solve);
/* ommitted */
}
}
}
You get the value for exAS by parsing solve through a regex.
If this returns a non-null value you've gotten a match
With that hen you go inside the if condition and do some logic
Still inside there, there is another if statement that checks if the regex matched anything. Now, by definition, this would be true - it can be easily seen with a lot of code removed - the same condition is checked for twice. There is nothing that would change the the outcome between the two ifs.
Since the conditional check passes you recursively call the same function again with the same input.
Because the input is the same, the logic will work the same so steps 1-5 are executed again and the function is called again.
This causes infinite recursion. Well, in reality there is a limit and that's the stack size for JavaScript, which is why you are getting the error. It's a bit misleading, since it's the regex that runs over the call stack size, not the recursive call to addSubtr, else it would have been a bit more clear what is going on.
For how to fix it - you need to restructure the logic so you don't get into infinite loops. I am not sure exactly what is the best way for your case but I'd suggest working it out yourself - it would be a useful exercise regardless. Here are some pointers
In point 4. I made, I mentioned that there was an essentially useless check. I assume that it is supposed to be useful.
- You may have intended the inner if to be outside of the outer one. As it stands now, the two are equivalent so the inner if can just be removed.
- maybe the condition of the inner if is incorrect - it could be that you only sometimes want to do the recursive call, not every time.
- perhaps there was supposed to be something that changes either exAS or solve or both. Thus either the condition would (potentially) yield a different result the second time it's checked, or the function would produce a different result when called recursively (which would make the recursive call useful) or both.
Your main problem is that you have an infinite loop which is here
if (exAS !== null) {
alg.addSubtr(solve);
}
This is a useless check for two reasons. One because as you notcie exAS is defined in addSubtr. So every time you call this function you are resetting the value.
Your other problems are you are create variables with the same names, and relying off of static variables/ void functions.
If pm me i cant help you workout the correct way to structure this this function and all the other functions .

variable is coming back as undefined jQuery

I am trying to call a function in jQuery and the variable is coming back as undefined in the console
var divide = function(entry) {
var entry = number
for (var i = 1; i <= entry; i++) {
if (i % 5 === 0 && i % 3 === 0) {
return "pingpong";
} else if ( i % 3 === 0) {
return "ping";
} else if (i % 5 === 0 ) {
return "pong";
} else {
return i;
}
}
}
$(document).ready(function(){
$("form#number").submit(function(event){
var number = parseInt($("#userNumber").val());
var pingpong = divide (number);
$("#result").text(pingpong);
event.preventDefault();
});
});
Why do you need a for-loop for this ? Assigning number to entry will not help as number is within the local scope of $(document).ready which will be undefined for divide. As you are passing entry as an argument, use that for conditions
Try this:
var divide = function(i) {
if (i % 5 === 0 && i % 3 === 0) {
return "pingpong";
} else if (i % 3 === 0) {
return "ping";
} else if (i % 5 === 0) {
return "pong";
} else {
return i;
}
}
$(document).ready(function() {
$("form#number").submit(function(event) {
var number = parseInt($("#userNumber").val());
var pingpong = divide(number);
$("#result").text(pingpong);
event.preventDefault();
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<form id='number'>
<input type="number" id='userNumber'>
<input type="submit">
<div id="result"></div>
</form>
Fiddle here
I think you may be confused about how arguments are passed into functions.
You have:
function divide ( entry ) { // defining divide
var entry = number; // this line is counter-productive
...
}
....
var number;
... divide(number); // calling divide
When you call the divide() function, the value of the variable number is automatically copied into the variable entry in divide(). Then you attempt to do the same thing with var entry = number; but number is not available in divide() so this fails. Lets suppose that number was globally available do this line did not cause an error. It might do what you want in this case, but a function whose argument is immediately ignored and overwritten is not very useful. Imagine you wanted to call it with two different values:
divide(number);
...
divide(someothernumber);
that wouldn't work because of the var entry = number; line -- you could never successfully pass someothernumber into divide(). Delete the line:
var entry = number;
from divide() and you will be much happier.
you try to delete "var entry = number"

Basic Public/Private function structure in JavaScript

I'm new to JavaScript. I want to implement recursion using two functions: one public, another private.
In Java, I'd always implement recursion like this
public int sumOfPrevious(int n){
return addNumbers(n);
}
private int addNumbers(int n){
if (n == 1)
return 1;
else
return n + addNumbers(n-1);
}
Then calling System.out.println(sumOfPrevious(5)) returns 15
But how do you implement something like that in JavaScript?
I tried this:
function sumOfPrevious(n){
return function privateFunc(n){
if (n == 1)
return 1;
else
return n + privateFunc(n - 1);
};
}
But calling console.log(sumOfPrevious(5)) just gives me [Function: privateFunc]
Why is it doing that and how do I fix this?
You need to declare the nested function and then use it, not return the nested function.
function sumOfPrevious(n){
function privateFunc(n){
if (n == 1)
return 1;
else
return n + privateFunc(n - 1);
}
return privateFunc(n);
}
You are returning the defined function itself.
Simply execute it :
function sumOfPrevious(n){
return (function privateFunc(n){
if (n == 1)
return 1;
else
return n + privateFunc(n - 1);
})(n);
}
A working example here at jsfiddle.
Hope it helps.
You return a function so you get a function...
To define private function you must create a class, as you do in Java, and then make the magic inside
function MyClass() {
var idx = this;
var my_private_member = 5;
this.my_public_member = 0;
function my_private_function() {
idx.my_public_member = my_private_member; //keyword "this" here won't reference to MyClass, but to the private function, so we keep a reference of MyClass to be accessed by the private function
}
this.my_public_function = function() {
my_private_function();
}
}
var my_instance = new MyClass();
my_private_member and my_private_function can't be accessed
Simply use a function for recursion:
JAVA and Javascript are two totally different things.
function sumOfPrevious(n){
if (n == 1)
return 1;
else
return n + sumOfPrevious(n - 1);
}
// call the function
console.log(sumOfPrevious(10)); // 55

What is the difference between naming functions or not in javascript?

What is the difference between
settings = {
edit: function (key, value) {
return anotherFunction(key, value) {
return value * 2;
};
}
};
and
settings = {
edit: function edit(key, value) {
return anotherFunction(key, value) {
return value * 2;
};
}
};
?
There's no difference when executing.
However, in the second case (named function), you can call the function recursively easier because it has a name.
For example, with a named function you can do:
fact: function factorial(n) {
if(n == 0) return 1;
return n * factorial(n-1); //You can do this with a named function easily
}
Without a name, this would be tricky.
Cheers
The essential difference is better debugging. In your developer tools, the named function in your second example will appear as edit in a backtrace; your first example will appear as anonymous. This can be extremely confusing when you're 10 function deep, and they are all called anonymous.
There are three reasons to give a function an inherent name. The first is that everyone does it. It's what everyone is used to.
function factorial(n) {
var accum = 1, i;
for (i = 1; i <= n; i++) {
accum *= i;
}
return accum;
}
The second is to understand stack traces better, as #meagar wrote.
The third is to let you write call functions recursively.
var factorial = function(n) {
var a = 1;
return (function factRecursive(k, a) {
if (k >= 2) {return factRecursive(k - 1, k * a)}
else {return a;}
})(n, a);
}

Is this the correct way to use an object with a function inside it?

Is this the correct way to create an Object and place a function inside of it? Every example I come across uses code that is to simple to understand and to use effectively in an actual situation. So I'm trying to figure this out by doing.
function calc() //creating an empty object named calc
{
}
var calc = new calc(); //creating a new instance of the calc object
calc.arithmetic = function maths (input)
{
var str = input;
var a=str.substr(1,1);
var b=str.substr(2,1);
var c=str.substr(3,1);
if(b == "+")
{
answerNumber = a + c;
}
else if(b == "-")
{
answerNumber = a + c;
}
else if(b == "*")
{
answerNumber = a * c;
}
else if(b == "/")
{
answerNumber = a / c;
}
}
document.getElementById("input").value=answerNumber;
document.write(calc.arithmetic(input)) //calling the method in the context of the object.
You're overwriting calc with a fresh object containing only myArithmetic here.
You should be doing calc.myArithmetic=function(){}; instead - this adds a new property with your function as value, which is probably what you want.
I would take a look at Douglas Crockford site (http://www.crockford.com/javascript/private.html).

Categories