Is there any way I can uniquely identify a function without giving it an expando property? I've been just using "toString()" to identify the function, but when two functions are identical, they conflict.
The following sample code reproduces the problem. In my actual code, the key for the associative array "myfunctions" is built from other parameters as well. I don't want to generate a meaningless key since the developers using this code need to be able to rebuild this key at any time without holding a reference to some random key.
var myfunctions = {};
(function(){
var num = 1;
function somefunc() {
alert(num);
}
myfunctions[somefunc.toString()] = somefunc;
})();
(function(){
var num = 2;
function somefunc() {
alert(num);
}
myfunctions[somefunc.toString()] = somefunc;
})();
for (var f in myfunctions) {
myfunctions[f]();
}
When this code is run, only one alert fires, and it always has the message "2".
The answer is no, there isn't any unique string value you can draw from a function with which you can associate that specific instance.
Why do you want to avoid using an expando?
I suspect that whatever you put in a property name (not a hash key, a property name) will be converted to string anyway.
This does not work either
(function(){
var num = 1;
function somefunc() {
alert(num);
}
somefunc.blah = 1;
myfunctions[somefunc] = somefunc;
})();
(function(){
var num = 2;
function somefunc() {
alert(num);
}
somefunc.bloh = 1;
myfunctions[somefunc] = somefunc;
})();
I just did some reading, and it seems like a property name can only be a string.
Related
This is a general question. But an answer in JavaScript would suit me the best.
I'm searching for a way to create variables after a pattern automatically.
For example, I want to create a while-loop in which a variable gets declared. In set loop, I want to create the variable car1. However, in the next loop pass I want to do the same thing BUT call the Variable car2 this time.
I'll try to write it in pseudocode:
//this should happen in the first loop
while(true){
var car1 = 1 + 2;
console.log(car1)
}
//this should happen in the second loop
while(true){
var car2 = 1 + 2;
console.log(car)
}
//In both cases "3" should be the output. But different Variables
Contrary to this example. I want to do all this in a single while loop. And on every while loop, a new variable should be created. So car1,car2,car3,car4.
Thanks in advance!
Maybe you can use an array and add an item every loop iteration or a hash map with a naming convention you set for the keys
You can try to use globalThis or window.
function nameFunction(name, f) {
return {
[name](...args) {
return f(...args)
}
}[name]
}
// use globalThis
for (let i = 1; i <= 3; i++) {
const funcName = `car${i}`;
const func =
nameFunction(funcName, () => console.log(`this is car ${i}`));
globalThis[funcName] = func;
}
car1(); car2(); car3();
// use window
for (let i = 4; i <= 6; i++) {
const funcName = `car${i}`;
const func =
nameFunction(funcName, () => console.log(`this is car ${i}`));
window[funcName] = func;
}
car4(); car5(); car6();
I hope this link will help you with this problem.
JS Dynamic Variable
Here they have discussed 2 ways of solving the problem. (One with "eval" and the other with "windows" object.
I think I have a pretty big logic issue here. A function return value isn't recognized by another function. I am not quite sure where the value that is returned by DoStuff goes...why can't I access the value numArray?
It is my understanding that all values inside a function are local to that function...unless I use return, which SHOULD allow me to access that value.
So this code is simply in an external js file...what you see is the only thing in it. My big question is when I return numArray...where does that value go?
function doStuff(){
//document.write("We are testing document writing now!");
let numArray;
let sumArray;
let start = parseInt(prompt("Enter a small number"));
let end = parseInt(prompt("Enter a larger number"));
if (start > end){
alert("Error: first int greater than last!")
} else {
let arraySize = end - start;
numArray = [start];
for (let x = start + 1; x <= end; ++x){
numArray.push(x);
}
console.log(numArray);
return numArray;
}
}
function addArray(numArray) {
console.log(numArray);
}
<form> <input type="button" value="Click Me to generate an array of numbers!" onclick="doStuff()"/> <input type="button" value="Click me to add the array numbers" onclick="addArray()"/> </form>
Console is telling me that numArray is undefined when I try to log it. I am needing to get the array (numArray) and use the data in the array to do some more things to them. Both functions are "called" by onclick buttons on a webpage (so I have to click the DoStuff button before the addArray button).
all values inside a function are local to that function...unless I use
return
Well, this is... partially true. First part is true and there is no "unless". return statement is just pointing to the value that is, well, returned by a function. It doesn't mean that this variable is now global. Value in return is kind of "value of function" and you must store it in a variable if you want to use it later, as you can see in others' answers.
call addArray function from DoStuff function and pass numArray as a parameter to it
function DoStuff() {
let numArray;
let sumArray;
let start = 1;
let end = 5;
if (start > end){
alert("Error: first int greater than last!")
}
else {
let arraySize = end - start;
numArray = [start];
for (let x = start + 1; x <= end; ++x){
numArray.push(x);
}
}
addArray(numArray)
}
function addArray(numArray){
console.log(numArray);
}
In your main js file that contains those onclick functions, you need to have a global variable to store your numArray after you call doStuff function.
Something like this:
let globalNumArray
// on click button doStuff
function (){
globalNumArray = doStuff()
}
// on click button addArray
function() {
addArray(globalNumArray)
}
My big question is when I return numArray...where does that value go?
The return value goes to where you called that particular function.
doStuff() is returning a value, so use the return of this function as a variable. We can assign this returned value to another variable or can use directly within expression. So call dostuff() to get the returned value.
function doStuff(){
//document.write("We are testing document writing now!");
let numArray;
let sumArray;
let start = parseInt(prompt("Enter a small number"));
let end = parseInt(prompt("Enter a larger number"));
if (start > end){
alert("Error: first int greater than last!")
} else {
let arraySize = end - start;
numArray = [start];
for (let x = start + 1; x <= end; ++x){
numArray.push(x);
}
console.log(numArray);
return numArray;
}
}
console.log('HERE IS ARRAY: '+doStuff());
Edit:
The reason why global variables are discouraged in js is, because all code has a single global namespace, where javascript has implied global variables automatically (like variables which are not explicitly declared in local scope are automatically added to global namespace). Relying too much on global variables can result in some collisions between scripts on the same page. This doesn't mean, that you mustn't use global variables but you shouln't use them light-mindedly. If you need a variable to be accessable after the function has finished, your choices are limited, so either use a global variable or pass the variable to the function you need it in.
You just need to save the result of doStuff and then access that variable in addArray:
var result
function doStuff() {
//document.write("We are testing document writing now!");
let numArray;
let sumArray;
let start = parseInt(prompt("Enter a small number"));
let end = parseInt(prompt("Enter a larger number"));
if (start > end) {
alert("Error: first int greater than last!")
} else {
let arraySize = end - start;
numArray = [start];
for (let x = start + 1; x <= end; ++x) {
numArray.push(x);
}
result = numArray; // save result for later (has to be a global scope)
}
}
function addArray() { // you defined this without an input in your form, so stick to that
if (result) // check if value exists
console.log(result);
else
console.log("Please enter the numbers boundaries first first.");
}
<form>
<input type="button" value="Click Me to generate an array of numbers!" onclick="doStuff()" />
<input type="button" value="Click me to add the array numbers" onclick="addArray()" />
</form>
Here's a couple things I think could help you out:
1) Split your code. doStuff, prompts the user for input, but it also generates an array containing values from min-max. You should have a separate function that generates an array from min to max. Splitting it up will make it easier to identify a problem.
2) A few solutions suggest a global variable this can be dangerous. When
you must share state limit its scope to only what needs to access that state.
3) Make your interfaces consistent. You should not return a value one instance and nothing in another. If there is an error make sure you are consistent with how you notify the caller.
function buildArray(start, end) {
let arr = [];
if (start > end) {
// There are a lot ways to deal with this
// But you want a consistent interface for letting
// the caller no that start < end
throw {
message: 'Start can\'t be bigger than end',
};
}
for (let x = start; x <= end; x++) {
arr.push(x);
}
return arr;
}
// encapsulate the variable numArray, so that it is only accessible
// to the methods that need it
var numArrayModule = (function(){
let numArray = [];
return {
doStuff: function(){
let start = parseInt(prompt("Enter a small number"));
let end = parseInt(prompt("Enter a larger number"));
try {
numArray = buildArray(start, end);
} catch(err) {
console.log(err);
}
},
addArray: function(){
console.log(numArray);
},
}
}());
// You may use these as onClick handlers as well.
numArrayModule.doStuff();
numArrayModule.addArray();
Currently I have a closure in JS that looks like the following:
var addTo = function(num){
var add = function(inner){
return inner + num;
};
return add;
};
var sum = new addTo(1);
My goal is to use the above closure to compute the sum from 1 all the way to 100 (i.e. sum = 1+2+3+...+99+100). Any help? I know a loop is needed, but am unsure of what should go inside the loop and how to use closure to achieve the goal. Thanks guys.
Currently I have a closure in JS that looks like the following:
All functions create closures, they're only remarkable when advantage is taken of them. ;-)
var addTo = function(num){
I don't know why function expressions are used when declarations are clearer (to me):
function addTo(num) {
then there's:
var add = function(inner){
return inner + num;
}
return add;
}
Which (sticking with an expression) can be:
return function (inner) {return inner + num};
}
Then you call it with new:
var sum = new addTo(1);
which causes addTo to create a new object that is not used, so you might as well do:
var sum = addTo(1);
which produces exactly the same result. So:
function addTo(num) {
return function (inner) {return inner + num};
}
var sum = addTo(1);
document.write(sum(3));
However, this is really just a version of Currying, so that sum will just add the supplied value to whatever was initially supplied to addTo.
If you want to add all the numbers from 0 to some limit, you just need a loop, no closure required:
function sumTo(num) {
var total = 0;
for (var i = 0; i <= num; i++) {
total += i;
}
return total;
}
document.write(sumTo(5)); // 15
Note that supplying a negative number will result in an endless loop, you should protect against that (I'll leave it up to you to work out how).
Try
function sum(x) {
var input = x;
function add(y) {
return input + y;
}
return add;
}
//var sum1 = sum(2);
//console.log(sum1(3)); // 5
console.log(sum(2)(3)); //5
Maybe you want to use recursive instead of loops?
function addTo(initial) {
function add(adder) {
if (initial < 100) {
initial+=1
return add(adder+initial)
}
else {
return adder
}
}
return add(initial)
}
document.write(addTo(1))
As long as the initial values don't go over 100, it would just add with sum of all calculation before + itself + 1.
It looks like the addTo() function returns another function into sum that will add whatever you pass it to the original number (or I assume that's what you meant to write; the first thing to do is change the statement inside of add() to use a += instead of just + to make sure you save the result).
Since you want to add each number from 2 to 100 (since you already passed 1 into addTo()), try writing a for loop that runs from 2 to 100 passing each one into the sum() function to add them all together. Here's an example:
var sum = addTo(1);
for (var i=2; i<100; i++) sum(i);
var result = sum(100);
Here I added 100 after the loop since I wanted to grab the final result. You could also add 100 in the loop and use sum(0) to get the result without changing it after the loop.
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;
}
I have a script setup like this (http://jsfiddle.net/YD66s/):
var countFull = new Array(0,1,2,3,4,5,6);
var countActive = new Array(0,1,2,3,4,5,6);
function pickRandom(a) {
if(arguments[1].length == 0) {
arguments[1] = arguments[0];
}
var m = Math.floor(Math.random()*arguments[1].length);
chosen = arguments[1].splice(m,1);
return chosen;
}
setInterval(function() {
pickRandom(countFull,countActive);
}, 1000);
When I run this I want the variable to be set for that function only. Instead it is affecting countFull towards the end because I make arguments[1] = arguments[0]. How in javascript can I just reference a variable but not consume it and ultimately arguments[1] becomes arguments[0].
Hope this makes sense. This is driving me nuts how different javascript variables are compared to other languages like PHP.
Javascript arrays are just pointers so when you do arguments[1] = arguments[0] you actually just set the pointer but the underlying arrays are the same. As a result, every time you modify arguments[1] you also modify arguments[0]. To do what you want, you need to copy the array. You could do it this way:
if (arguments[1].length == 0) {
for(var i = 0; i < arguments[0].length; i++) {
arguments[1][i] = arguments[0][i];
}
}
To copy an array, instead of referencing it, use copy = original.slice(0).