Named vs nameless function for replacing numbers in a string - javascript

I am a JavaScript beginner, and one of the problems in the latest programming assignment I got is to replace all numbers in a string with sum of their digits, so, for example, for an input like this:
"m123a"
the output should be
"m6a"
I actually managed to write a working code, but I do not understand why it works.
This is my HTML:
<html>
<TEXTAREA ID = "text" ROWS = 10 COLS = 30></TEXTAREA>
<br>
<INPUT TYPE = "button" ID = "button" VALUE = "Replace">
<SCRIPT src = "zaz3.js" type="text/javascript"></SCRIPT>
</html>
This is my working JavaScript code:
function ReplaceNumbers()
{
var s = document.getElementById("text").value;
document.getElementById("text").value = s.replace(/\d+/g, function DigitSum(x)
{
var sum = 0;
while (x > 0)
{
sum += x%10;
x = x/10;
x = Math.floor(x);
}
return sum;
});
}
var button = document.getElementById( "button");
button.addEventListener("click" , ReplaceNumbers);
And this is the first version of my JavaScript code which does not work:
function DigitSum(x)
{
var sum = 0;
while (x > 0)
{
sum += x%10;
x = x/10;
x = Math.floor(x);
}
return sum;
}
function ReplaceNumbers()
{
var s = document.getElementById("text").value;
document.getElementById("text").value = s.replace(/\d+/g, DigitSum(x));
}
var button = document.getElementById( "button");
button.addEventListener("click" , ReplaceNumbers);
The only difference here is that function DigitSum is implemented separately in the second version.
When debugging the second code, the error returned is "ReferenceError: x is not defined". I do not understand how the parameter x in the first code is even interpreted since it's not mentioned anywhere else in the code.
So, my question is, what is the difference between implementing the function DigitSum separately vs implementing it where it is needed, and what actually is x in the first version, and what is it in the second version.

because in the second one you are calling the function and whatever it returns is being assigned to the replace. In your case you should have an error that says "x is undefined".
document.getElementById("text").value = s.replace(/\d+/g, DigitSum(x));
It should just be
document.getElementById("text").value = s.replace(/\d+/g, DigitSum);

You are using a callback
document.getElementById("text").value = s.replace(/\d+/g, DigitSum(x));
// ^^^^^^^^^^^
but instead to use only the function reference, you insert a call of the function with x, which does not exist.
Use this for a valid reference of a callback.
document.getElementById("text").value = s.replace(/\d+/g, DigitSum);
// ^^^^^^^^ without parenthesis
A calback is a function which is used for repeating calls with a fixed parameter list. The surrounding function defines the parameters and in this case you may have a look to String#replace.

Related

Why is a Javascript function without declared parameter working?

I'm writing a hangman game. With the help of Google I have a function to check if a letter is in the word, but I don't understand how, although I never declare the parameter "chosenLetter" of my function, this is able to give "chosenLetter" exactly the value of the specific letter I click on. Nor how "getElementById(chosenLetter)" can pick exactly the letter I click on to disable the button.
Same thing with the "guessedWord" function, where "letter" is never declared, yet it selects a letter to check for in the "guessed" array
let answer = '';
let maxWrong = 5;
let mistakes = 0;
let guessed = [];
let wordStatus = null;
function guessedWord() {
wordStatus = answer.split('').map(letter => (guessed.indexOf(letter) >= 0 ? letter : '_')).join('');
document.getElementById('word').innerHTML = wordStatus;}
function generateButtons() {
let buttonsHTML = 'abcdefghijklmnopqrstuvwxyz'.split('').map(letter =>
`
<button
class = "btn"
id = '` + letter + `'
onClick = "handleGuess('` + letter + `')"
>
` + letter + `
</button>
`).join('');
document.getElementById('alphabet').innerHTML = buttonsHTML;}
function handleGuess(chosenLetter) {
if (guessed.indexOf(chosenLetter) === -1) {
guessed.push(chosenLetter)
} else {
null;
}
document.getElementById(chosenLetter).setAttribute('disabled', true);
if (answer.indexOf(chosenLetter) >= 0) {
guessedWord();
checkIfGameWon();
} else if (answer.indexOf(chosenLetter) === -1) {
mistakes++;
updateMistakes();
checkIfGameLost();
}}
As I'm new at javascript, I'm generally trying to understand how is it possible that parameters not declared can seem to declare themselves so specifically? I don't know if I'm asking the wrong question, but that's the only thing in the code which I can't understand nor explain
You need to read this documentation first.
It says
The map() method creates a new array populated with the results of calling a provided function on every element in the calling array.
If we try to break the following statement in separate statements,
wordStatus = answer.split('').map(letter => (guessed.indexOf(letter) >= 0 ? letter : '_')).join('');
You will find,
let splittedAnswer = answer.split(''); // This will split the answer string and crate an array with all the characters in answer.
const callbackFunction = (letter) => {
return guessed.indexOf(letter) >= 0 ? letter : '_';
}
let newArray = splittedAnswer.map(callbackFunction);
let joinedString = newArray.join('');
As you can see you are declaring a callback function. You are passing that function to the array.map() method. Now the array.map() method will call the function with 3 params currentItemInTheArray, currentIndex, theSourceArray. As you have declared only the first param in your callbackFunction i.e. currentElementInTheArray you will get the first param. You could declare your callback array like this,
const callbackFunction = (item, index, arr) => {
console.log(item);
console.log(index);
console.log(arr);
}
And now if you call
[1,2,3].map(callbackFunction);
You will get the following output,
1 //currItem
0 //index
[1,2,3] //source array
2 //currItem
1 //index
[1,2,3] //source array
3 //currItem
2 //index
[1,2,3] //source array
But you are doing it inline, that is why you were not following. I hope now it is clear to you.
This is how functions work, you pass an argument as an input and to use that argument in your function you use parameters in the function definition which act as placeholders for your input and then you can use the parameters anywhere inside your function.
Example: In the function guessedWord(), you are using a map function which takes a callback function as an argument. So the work letter is actually the parameter of the callback function and parameters don't need declaration they are just placeholders.
generateButtons is going to insert into the HTML element "alphabet" something that looks like this:
<button
class = "btn"
id = 'a'
onClick = "handleGuess('a')"
>
a
</button>
<button
class = "btn"
id = 'b'
onClick = "handleGuess('b')"
>
b
</button>
...
Those onClick handlers will be function that pass the various letters as the first (and only) argument to handleGuess.
handleGuess is a function declared to take a single parameter, which is known internally to the function as chosenLetter. But when you call it, you do not have to pass it a variable with the name chosenLetter. Javascript doesn't care about that. You could pass it a variable named foobar and it would be fine, or you could just pass it the raw value.
For a simpler example, let's say we had a simple function:
function area (height, width) {
return height * width
}
we could call it in various ways, including:
const height = 5;
const width = 8;
area (height, width) //=> 40
// or
const h = 6
const w = 7
area (h, w) //=> 42
// or
const rectangle = {
height: 3,
width: 10
}
area (rectangle.height, rectangle.width) //=> 30
// or simply
area (4, 9) //=> 36
The same principle applies to handleGuess
in JavaScript
variables that don't get declared will get automatically assigned to the global scope
is simple words it will declare it self :)
in your case something different is happening
you are passing the letter as a parameter to the function
onClick = "handleGuess('` + letter + `')"
and this is why it makes all the magic come alive :)
the same goes to the id property
id = '` + letter + `'
passing the information about which specific letter you are pressing on make it so that the JavaScript Engine know which button is being pressed and that is how it know what letter you chose and what he need to disable

While operator undefined

I want to make a small calculator in javascript.
I got the html code looking like this (for all the numbers)
<button type="button" onclick="calcNum(1)">1</button>
<button type="button" onclick="operator('+')">+</button>
var myNumbers = [];
The calcnumber function like this:
function calcNum(i) {
myNumbers.push(i);
var x = document.getElementById("screen").innerHTML = myNumbers.join("");
}
and the operator function like this:
function operator(op) {
var operator = op;
var y = document.getElementById("screen").innerHTML = operator;
}
My goal is to make it like this:
If I press 1,2,3 I want the screen element to display "123" (which it does) if I press "+" I want "+" to be displayed (which it does) however when the operator is pressed, and then a new number is pressed I want it to start on a new number, right now if I press "123" and then + and then "456" I get:
123456, instead I want it to display "456", hence starting on a new number. Hope it's all clear.
I figured I could add this to the calcNum function:
while(op == "undefined") {
keep pushing numbers // but this does not work
}
In the end I want to construct a calc function which takes all the numbers up to a operator is pressed as the FIRST number, then concatanate with the operator and the second number and adding them together.
I see several issues in your code but I don't know if it is due to the fact that you didn't copy all your code in your question.
First, the operator function is incorrect : you give a local variable the samename than the function. If you want the function return a value, use the returnkeyword.
I figured I could add this to the calcNum function:
while(op == "undefined") { keep pushing numbers // but this does
not work }
Where is opdefined? The only op I see is a local variable of the operatorfunction. It will always be undefined in calcNum.
Note also that if you want to test if a variable is undefined, you should not test
if (myVar == "undefined")
but
if(typeof myVar == "undefined")
Finally I'd change your code this way (should be tested though):
var currentNumber= "";
var entries = []
function calcNum(i) {
currentNumber +=i;
document.getElementById("screen").innerHTML = currentNumber;
}
function operator(op) {
var y = document.getElementById("screen").innerHTML = op;
//Note that you could already process the entered operations as if you clicked on '='
//and display the result instead of displaying the operation...
if(currentNumber != ""){//there must be a number entered before you click on an operator
entries .push(currentNumber);
entries .push(op);
currentNumber= "";
}
}
And you still need of course to implement what you do when you click on =...
Change your functions like this
var numbers = "";
function calcNum(i) {
myNumbers.push(i);
numbers +=i;
var x = document.getElementById("screen").innerHTML = numbers;
}
and
function operator(op) {
var operator = op;
var y = document.getElementById("screen").innerHTML = operator;
myNumbers.push(op);
numbers = "";
}
Declare above:
var leftOperand = null;
var lastOperator = null;
In calcNum:
if(lastOperator !== null) {
document.getElementById("screen").innerHTML = '';
leftOperand = myNumbers.join('');
myNumbers = [];
lastOperator = null;
}
// rest of the function
In operator:
lastOperator = op;
// rest of the function

Javascript toFixed is not a function

Hi the problem is following:
I define:
var total = 0;
function add(a){
total+=a;
var float_num = total.toFixed(2);
return float_num;
}
The JS give me an error said Uncaught TypeError total.toFixed is not a function
I don't get it. the total I declare is not a number type?
I think the easiest way to prevent the error from happening is to always parse the parameter as number:
var total = 0;
function add(a){
total+=a;
var float_num = Number(total).toFixed(2);
return float_num;
}
Check if any of the code above has redefined the toFixed on the Number prototype, For instance
Number.prototype.toFixed = {};
var total = 0;
function add(a) {
total += a;
var float_num = total.toFixed(2);
return float_num;
}
add(2)
is one way to replicate the error.
It depends on the value of a. If a happens to be a "string" then you're trying to do:
"0string".toFixed(2)
which should throw an error.
This works:
var total = 1.0;
function add(a) {
total += a;
var float_num = total.toFixed(2);
return float_num;
}
console.log(add(4.89));
This code is a bit unsafe since you assume that a is a float and not a string.
https://jsfiddle.net/6to7kbbm/
This will throw the exception:
var total = 1.0;
function add(a) {
total += a;
var float_num = total.toFixed(2);
return float_num;
}
console.log(add("4.89"));
Okay, so I've just run your code a few times, and I can confirm that your .toFixed() line is working just fine.
However, it only works if you pass a numeric value into the function. If the a parameter is not numeric, then toFixed() will fail as described.
So the problem isn't with the function, but how you're calling it. In your question, you're not showing how you're calling the function, so I can't give you any direct guidance on that, other than to make sure that you're giving it a numeric every time.
Maybe you're passing in a string? That would break things (even if the string does contain a numeric value).
Or maybe it's a null or undefined or NaN due to an error or oversight elsewhere in your system? I can't tell, but in those cases you probably don't want to be calling the add() function at all.
I found the problem. My some other function has a code that xxx.text(total). It actually convert total back to string. That cause the problem.
Thanks for all your help!
Verify if you have any declared function with the same name as the variable you are using. To prevent this you may declare global variables like:
var global_variable = 0;
function myfunction()
{
var variable = 0;
global_variable = variable + 1;
}

Can I use a string variable in document.getElementById()?

here is my code:
function figureSelector () {
document.getElementById("rook").onclick = function () {
curr = '"rook"';
};
};
function moveLine(){
document.getElementById("upButton").onclick = function() {
document.getElementById(curr).style.top = document.getElementById(curr).offsetTop - getPix() * 62 + "px";
counter= counter + getPix();
};
I want to write an universal function for a chess piece to move. All I want is, when one clicks the chess piece, and then presses the up button, it must go up.
Yes you can use String variable:
HTML:
<div id="name" style="width:300px;height:300px;background:red"></div>
javascript:
var b = 'name';
document.getElementById(b).innerHTML = 'none';
jsfiddle here
Yes, you can.
Just use
curr = 'rook';
(without the extra quotes)
You can even do stuff like this:
function mark(yy) {
for (var ii = 0; ii < 7; ii++ ) {
if ( ii == yy ) {
document.getElementById("b"+ii).style.fontWeight = "bold";
}
...
But be careful of your loop limits to be sure you have a matching id. I just spent hours trying to figure out why ("b"+ii) was getting error and finally realized that the error was being caused by exactly that. duh...
Yes, Mate, you can.
You can use a variable as the argument for any function. That's just how functions work -- they don't care where the argument comes from. You should define curr outside those functions.

I am getting Error from For Loop function in Javascript

this is a function to call SELECT element values. but i am facing an error.
code is here.
function get_s_val(){
var foo = all_categories_1;
var ov1 = "";
for(m=0;m<=foo.length;m++){
ov1 += foo[m].value+',';
}
console.log(ov1);
var tme=setTimeout("get_s_val()", 1000);
}
get_s_val();
it shows an error like "Uncaught TypeError: Cannot read property 'value' of undefined"
but when i do some littel changes it works.. like
function get_s_val(){
var foo = all_categories_1;
var ov1 = "";
//for(m=0;m<=foo.length;m++){
ov1 += foo[0].value+',';
//}
console.log(ov1);
var tme=setTimeout("get_s_val()", 1000);
}
get_s_val();
i dont know that where i am wrong to write the code.
Modify your loop condition to run while the iterator is less than the length of the array, or you'll get undefined when you hit the non-existent element at index foo.length:
for(var m=0;m<foo.length;m++){
ov1 += foo[m].value+',';
}
...and always declare variables with the var keyword, or bad things will happen, and JSLint will whine about it (and rightly so, but that's another topic).
function get_s_val(){
var foo = all_categories_1;
var ov1 = "";
for(var m = 0; m < foo.length; m++){ // use var, and only loop from e.g.
// 0 to 2 when the length is 3, so <,
// not <=
ov1 += foo[m].value+',';
}
console.log(ov1);
setTimeout(get_s_val, 1000); // don't use a string, just pass the function.
// Plus, the variable is nowhere accessible so
// you can drop storing it
}
get_s_val();
Anyway, if you simply want to join the array's elements into a string with , as delimiter, why not do:
console.log(foo.join());
At the top of the for loop, m<=foo.length; should instead be m<foo.length;.

Categories