I'm trying to call a function from this:
var _coll = [new Obj('a', somefunction)];
function Obj(id, fn) {
this.id = id;
this.fn = fn;
}
var somefunction = (function () {
return {
innerFn: function (a) {
return a
}
}
})();
//this works
var test = new Obj('a', somefunction);
alert(test.fn.innerFn('test'));
//this is not working
loopArray();
function loopArray()
for (var it in _coll) {
for (var its in _coll[it]) {
var response = _coll[it].fn.innerFn('hey');
alert(response);
}
}
}
If I change _coll to "var test=new Obj('a','somefunction');", its ok, but how do I call a function?
Because at the point where you define _coll, the function somefunction is not yet defined.
If you move the call which defines somefunction to top of the code, it will work just fine.
First off you're using a for..in loop to access an array, which you should never do, but aside from that...
Within the first loop, _coll is the array so _coll[it] would be an element of that array. That element is your Obj object. Your second for..in loop is completely unnecessary and wrong. Surely you can see that you're doing something wrong, since you define a its variable that's never used...
Additionally to what Kolink said about the loop,
you need to move the line
var _coll = [new Obj('a', somefunction)];
behind the declaration of somefunction like you did with the line
var test = new Obj('a', somefunction);
or somefunction will be undefined.
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 am using modular pattern of javascript and trying to do things in Javascript way rather than Jquery
myapp.module1 = (function($){
"use strict";
var _config = {
backgroundImages : document.getElementsByClassName('img_paste'),
}
for(var i = 0;i < _config.backgroundImages.length; i++){
var imageElement = _config.backgroundImages[i];
imageElement.addEventListener('click',myapp.module2.addBackgroundImage(imageElement),false);
}
// $('.img_paste').click(function(){
// var img = this;
// console.log(this);
// console.log($(this));
// myapp.module2.addBackgroundImage(img);
// });
})(jQuery);
In the above code, the Jquery click function works but not the Javacript one.
When I tried to debug, I tried to console out the image in addBackgroundImage() function.
var addBackgroundImage = function(imageToBeAdded){
console.log(imageToBeAdded);//
_addImageToCanvas(imageToBeAdded);
}
The function seems to be executing even before onclick. Why is that happening?
First, the images elements appear to be empty in the console, then after some some the image elements are displayed in console.
Take a look at this simple code example:
function describeTheParameter(p) {
console.log("describeTheParameter invoked. p is of type " + typeof(p));
}
function stringFunction() {
return "Hello World!";
}
describeTheParameter(stringFunction());
describeTheParameter(stringFunction);
This results in
describeTheParameter invoked. p is of type string
describeTheParameter invoked. p is of type function
In the first call, we are calling stringFunction, and then passing the result to describeTheParameter.
In the second call, we are actually passing the function to describeTheParameter.
When you call addEventListener you must follow the pattern of the second call: pass the function without invoking it:
In the following line of code, you are invoking addBackgroundImage, and then passing the result (which will be undefined) to addEventListener.
imageElement.addEventListener('click',myapp.module2.addBackgroundImage(imageElement),false);
You need to pass a yet-to-be-called function into addEventListener.
The smallest step to make your code work is to employ a currying function:
function addImage(imageElement) {
return function() {
myapp.module2.addBackgroundImage(imageElement);
}
}
for(var i = 0;i < _config.backgroundImages.length; i++){
var imageElement = _config.backgroundImages[i];
imageElement.addEventListener('click', addImage(imageElement), false);
}
For much simpler code, make use of the this keyword. In this case, this will point to the element that's firing the event.
function imageClickHandler() {
var imageElement = this;
myapp.module2.addBackgroundImage(imageElement);
}
for(var i = 0;i < _config.backgroundImages.length; i++){
var imageElement = _config.backgroundImages[i];
imageElement.addEventListener('click', imageClickHandler, false);
}
The function seems to be executing even before onclick. Why is that happening?
Look at the statement you wrote:
myapp.module2.addBackgroundImage(imageElement)
You are calling the function and then passing its return value as the function argument.
You want something more along the lines of:
myapp.module2.addBackgroundImage.bind(myapp.module2, imageElement)
(or the function expression that you used in the commented out code)
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
Alrighty... so there's a couple things going on here. First, I'm trying to create a global object called myScrolls. Second, I'm trying to set the value of that global object inside a jQuery load function. Third, I'm trying to access the myScrolls object outside of the load object.
What am I missing? Do the 'for' loops have limited scope?
Thanks
myScrolls=new Object();
$(window).load(function () {
var projectCount = 5;
for (var i=0;i<=projectCount;i++)
{
var singleProject = 'project_' + i;
myScrolls[singleProject] = new iScroll(singleProject, horizontalPreferences);
}
});
console.log(myScrolls);
You're trying to read the object before the load callback executes.
That $(window).load() function is waiting until after the window loads, and because the console log is not also in that callback, it actually gets executed before the function does. Thus by the time the console statement runs, its actually not populated.
myScrolls=new Object();
$(window).load(function () {
var projectCount = 5;
for (var i=0;i<=projectCount;i++)
{
var singleProject = 'project_' + i;
myScrolls[singleProject] = new iScroll(singleProject, horizontalPreferences);
}
console.log(myScrolls); //this was out of scope when outside of $(window).load()
});
function Something() {
this.var1 = 0;
this.var2 = 2;
this.mytimer;
this.getCars=function() {
//some code
};
this.start = function(l) {
this.updateTimer=setInterval("this.getCars();" , 5000);
};
}
var smth = new Something();
smth.start();
When I type in this.getCars() it does not work. if the function is global declared and i put in for example just getCars it works.
I don't know how to work out this problem because setInterval becomes as parameter a String.
Can somebody help me put with this?
var me = this
setInterval(function() {me.getCars()}, 5000)
if you happen to be using prototype, you could also use the handy bind method:
setInterval(this.getCars.bind(this), 5000)
Try this:
function Something() {
this.var1 = 0;
this.var2 = 2;
this.mytimer;
var me = this;
this.getCars = function() {
console.log(me.var2);
};
this.start = function(l) {
me.updateTimer = setInterval(me.getCars, 1000);
}
}
var smth = new Something();
smth.start();
The console.log() bit is Firefox/Firebug. Replace it with something else if you're not using that (although I would highly recommend developing with it).
Basically the problem is that when you call a function, even a method of an object, the way you call it determines the value of this. See Method binding for more details. So what you do is fix the value of this as I've done in the above example (for methods).