I'm working on a code where I must pass a different function to some objects.
In this case, I'm trying to pass a different function for the onchange event. So currently what I got is something like this this:
var ArrayList; //Contains some data to use with ObjectArray format { n: data }
var ObjectArray; //Contains several objects format Array[n] = Object;
for(var key in ArrayList){
var doFunction = function() {
Object[key].doSomething(ArrayList[key]);
}
Object[key].onchange = doFunction;
}
The problem here I believe is that I'm afraid it will execute the code as it is declared and not with the values of the actual variables.
Is there a way to pass the function with the values as it executes? or will the variables get parsed the way its written?
It's the classic function in a loop problem. You need to understand how closures work.
Read the "Example 3" part of this answer carefully. The whole How do JavaScript closures work? question, too.
Another example that might help understand intuitively:
var key = 5;
var onchange = function () {
console.log(key);
};
onchange(); // 5
key = 10; // the loop reassigns the key on each iteration
onchange(); // 10
This is how it should be done:
var ArrayList; //Contains some data to use with ObjectArray format { n: data }
var ObjectArray; //Contains several objects format Array[n] = Object;
for(var key in ArrayList)
{
(function(key)
{
var doFunction = function()
{
Object[key].doSomething(ArrayList[key]);
}
Object[key].onchange = doFunction;
}(key))
}
Related
I have an API that takes a function as an input, and then inside the API, the intent is to add the function to an Array if the function is not already added to the Array.
The call to the API is of the form:
myApiHandle.addIfUnique(function(){
myResource.get(myObj);
});
The API is:
myApiHandle.addIfUnique(myFunc) {
if (myArray.indexOf(myFunc) === -1) {
return;
}
// add to array
}
Now this obviously does not work as expected, since each time a new function is being passed in.
My Question is: Is there a way to pass in a function into the myApiHandle.addIfUnique call that will allow me to compare the existing functions in the array with this function that is currently passed in? The comparison should compare the function name and the object, and if both are the same, then not add the function to the array. I want to avoid adding another argument to the addIfUnique call if at all possible.
In other words, is the below possible:
myApiCall.addIfUnique (someFunc) {
}
If so, what is the someFunc. And what would be the logic inside the API to detect if the function already exists in myArray?
The same problem occurs with addEventListener and removeEventListener, where the callback must be identical (in the === sense) for removeEventListener to remove it.
As you've found, obviously if you call addIfUnique like this:
addIfUnique(function() { })
the function passed each time will be a unique object. The solution is to create the function once:
var fn = function() { };
addIfUnique(fn);
addIfUnique(fn);
A related problem occurs when the function being passed in is a method invocation, so I need to bind it:
var x = { val: 42, method: function() { console.log(this.val); } };
I want to pass a bound version of it, so
addIfUnique(x.method.bind(x));
addIfUnique(x.method.bind(x));
But again, each call to x.method.bind(x) will return a separate function. So I need to pre-bind:
var boundMethod = x.method.bind(x);
addIfUnique(boundMethod);
addIfUnique(boundMethod);
First of all, comparing functions is meaningless, even if two functions are literally different, they may be functionally the same.
And for your problem, you can compare whether it's exactly the same object, or you can compare it literally by using toString() function and regExp.
var addIfUnique = (function() {
var arr = [];
return function(func) {
if (~arr.indexOf(func)) return false;
var nameArr = [];
var funcName = func.name;
var funcRegExp = new RegExp('[^\{]+\{(.+)\}$', 'i');
var funcStr = func.toString().match(funcRegExp);
funcStr = funcStr && funcStr[1];
if (!funcStr) return false;
var strArr = arr.map(function(v){
nameArr.push(v.name);
return v.toString().match(funcRegExp)[1];
});
if (~strArr.indexOf(funcStr) && ~nameArr.indexOf(funcName)) return false;
arr.push(func);
};
}());
I've tried to search for an answer to my question, but I'm starting to think that, given the lack of results, I'm obviously not expressing the question properly. With that in mind, apologies if the title of this post is misleading, I am still very much learning.
I have a simplified version of my code below
var testData = ['a', 'b']
var addReceiver = (function () {
dataReceiver = function (dataInput) {
t = this
t.data = dataInput;
console.log(t.data);
t.interval = setInterval(function () {
t.update();
}, 1000);
t.stopUpdate = function () { clearInterval(t.interval); };
t.update = function () {
//t.data = dataInput;
console.log(t.data);
};
};
})()
var testLogger = new dataReceiver(testData);
</script>
The behaviour that I wish to emulate is when I type into the console
testData = ['c','d','e']
for testLogger to log the array ['c','d','e'] every second rather than ['a','b'].
I could change
t.data = dataInput to t.data = testData
to achieve this, but that would obviously be pointless, or else every new instance I created of dataReceiver would have a reference to the same data input.
So, my question is, how would I need to change the code to provide the testLogger vairable (or any instance of dataReceiver) access to a variable outside of its local scope?
Use the object that you have created instead of accessing the global variable,
var testLogger = new dataReceiver(testData);
testLogger.data = [1,2,3,4];
Now you will be able to print the newly injected data. I mean the setInterval will print the updated value.
I have a function that create and store an array for all the p elements:
function dummyArray(){
var $dummy= $('p');
var dummy= [];
i = 0;
$dummy.each(function()
{
dummy[i++] =$(this).html();
});
return dummy;
}
Now, in order to reuse the array in another function, I can use dummyArray() and dummyArray()[0] to access the individual data.
function initAll(){
//dummyArray();
//dummyArray()[0];
}
However I want to store it inside a variable like below but it gives me error.
function initAll(){
var allArray = dummyArray();//error
}
Is there a way to store it inside a variable or is there a better way of doing this?
After cleaning up my code I noticed that using var allArray = dummyArray(); does work, the error was generated from something else. cheers~
Edited:
The error I found out was the function name cannot be the same as the new variable name declared even though the () aren't there.
var dummyArray = dummyArray();//error
var allArray = dummyArray();//works
This is some JS code
var methodArr = ['firstFunc','secondFunc','thirdFunc'];
for(var i in methodArr)
{
window[methodName] = function()
{
console.log(methodName);
}
}
My problem is that how to get the name of a function in JS.
In JS, use this.callee.name.toString() can get the function name. But in this situation, it is a null value. How can i get the 'funName' string?
Sorry, I didn't make it clear.
I want to create functions in a for loop, all these functions has almost the same implementation which need its name. But others can call these functions use different name.I want to know what methodName function is called.
it seems a scope problem.
Try this:
var methodArr = ['firstFunc','secondFunc','thirdFunc'];
for(var i in methodArr) {
var methodName = methodArr[i]; // <---- this line missed in your code?
window[methodName] = (function(methodName) {
return function() {
console.log(methodName);
}
})(methodName);
}
window['secondFunc'](); // output: secondFunc
I want to merge a argument of a function with a variable
But i don't know how to do that.
firstDates = [];
function myFunction(partOne) {
partOne + Dates.push(someOtherVar);
}
myFunction(first);
I know that this not works, but what would be the right way?
why not something like this?
var dates = {};
function myFunction(partOne) {
dates[partOne] = []; // dates["first"] = []
dates[partOne].push(someOtherVar); // dates["first"].push(someOtherVar)
}
myFunction("first");
Otherwise what you are trying to accomplish is an eval type of set up. This is generally a very bad idea. Don't use dynamically named variables.