I just to wanted to call a function inside a self-executing anonymous function. Whenever I try to call a function, I am getting an error saying "Uncaught TypeError: createGesture() is not a function"
loadGesturesFromDatabase: function() {
var firebaseRef = new Firebase("https://test.firebaseio.com/");
this.loadFromFireBase(firebaseRef);
firebaseRef.on('value', function(dataSnapshot) {
dataSnapshot.val();
console.log(dataSnapshot.val()); // console showing the data //which fetched from firebase
//Only having issue when executing following line of code
this.loadJson(JSON.stringify(dataSnapshot.val()));
});
}
loadJson: function(json) {
}
The provided code is not much to go by, but the error is probably caused by the fact that you refer to this inside an anonymous function.
this.loadJson(JSON.stringify(dataSnapshot.val()));
Try storing the this out of the anonymous function, and then using it in the anonymous function, like so
loadGesturesFromDatabase: function () {
var firebaseRef = new Firebase("https://test.firebaseio.com/");
//We keep a reference to the correct this
var _this = this;
this.loadFromFireBase(firebaseRef);
firebaseRef.on('value', function(dataSnapshot) {
dataSnapshot.val();
console.log(dataSnapshot.val()); // console showing the data //which fetched from firebase
//You are now referencing the correct this
_this.loadJson(JSON.stringify(dataSnapshot.val()));
});
}
As a note, there are no self invoking functions in the code you provided. A self invoking function looks like this
(function() {
//code
})()
Mitch identified the problem: since you have a callback function, the meaning of this changes. You can explicitly set the value of this by using bind():
firebaseRef.on('value', function(dataSnapshot) {
this.loadJson(JSON.stringify(dataSnapshot.val()));
}.bind(this));
See: Use of the JavaScript 'bind' method
Related
I'm trying to set a field's value to a function, then execute it. this.fetchLocalStorage is not a function is what I get from running it.
var app = {
busdata: (function(){return this.fetchLocalStorage()})(),
fetchLocalStorage: function() {
//fetching
return "fetching data...";
}
};
console.log(app.busdata);
Note that by not making it a self-executing function, it works, but then it would mean the function is called everytime when I only need to fetch the data one time.
busdata: function(){return this.fetchLocalStorage()}
/* ... */
console.log(app.busdata()); //this calls the function every time :(
Thought it might a context problem so I tried a couple things with bind and call but with no luck.
Am I missing something?
this is only bound to the object when you call a method of the object, i.e. app.someMethod(). But you're trying to call fetchLocalStorage() when you're creating the object, not in a method of the object, so this is whatever the outer context is, which is likely the global window object.
You can't refer to other properties of the object until after the object has been created. So just call the function normally after you create the object.
var app = {
fetchLocalStorage: function() {
//fetching
return "fetching data...";
}
};
app.busdata = app.fetchLocalStorage();
I think your params were on the wrong side of the brace.
busdata: (function(){return this.fetchLocalStorage()}() ),
Relevant fiddle: https://jsfiddle.net/tqf4zea7/1/
I'm using $q in an angular controller. To test some scenarios, I created an array on the scope to push messages to:
$scope.messages = [];
I have set up a function that returns a $q function as so:
function returnAPromise(valToReturn){
return $q(function(resolve, reject){
$timeout(function(){
resolve(valToReturn);
}, 500);
});
}
I then have a .then() call on the result that looks like this:
returnAPromise('third').then($scope.messages.push);
Since I only want to push the value that the promise was resolved with to the array, I figured I could just pass in the push method of the messages array, but when I do that, I get the following error:
VM289 angular.js:12520 TypeError: Array.prototype.push called on null or undefined
at processQueue (VM289 angular.js:14792)
at VM289 angular.js:14808
at Scope.$eval (VM289 angular.js:16052)
at Scope.$digest (VM289 angular.js:15870)
at Scope.$apply (VM289 angular.js:16160)
at VM289 angular.js:17927
at completeOutstandingRequest (VM289 angular.js:5552)
at VM289 angular.js:5829
If I enclose push in a function, it works fine:
returnAPromise('third').then(function(message){
$scope.messages.push(message)
});
Is this a closure issue I don't understand?
You need to bind push since it uses this
returnAPromise('third').then($scope.messages.push.bind($scope.messages));
I know there is an accepted answer, but i will explain this more clearly here
Example
lets start with an example
var scope = {
scopeFn: function() {
console.log('this', this)
}
}
function callFn(fn) {
fn();
}
callFn(obj.scopeFn) // will log window object
callFn(function() {
obj.scopeFn();
});// will log scope object
as you can see, wrapping the function will give the called object the value of this, but calling it directly without wrapping it will call the window object.
why?
this will bind to the object its called from.
In the first example callFn(obj.scopeFn) you are passing the function as a parameter, hence when the function is called, its called directly not from the scope object. (scope object is lost, only the function reference is sent).
in the second example you are calling the function scopeFn from the object, hence the this will bind to its object. (scope object is not lost, as the whole thing is there when its called)
Solution
To solve this issue you need to bind the function you are passing as a parameter for the resolve, so it will always be called as if it is called from its parent object.
var scopeMessage = $scope.messages;
returnAPromise('third').then(scopeMessage.push.bind(scopeMessage));
Im trying to add an event listener to a object for example:
this.startLoading = function(){
this.a.addEventListener("complete", this.loadingHandler()); this gives me an error
},
this.loadingHandler = function(){
console.log("im doing something")
}
ERROR: "Uncaught Error: addListener only takes instances of
Function. The listener for event "complete" is "undefined"
However if I put the loadingHandler() function inside the scope it works, for example:
this.startLoading = function(){
var loadingHandler = function(){...}
this.a.addEventListener("complete", loadingHandler()); // this works
},
Im not sure what instances of a function means in that regard?
When you put () after a reference to a function, that means to call the function, and the value of the expression is whatever the function returns.
Your second example, that you say works, actually will not work, and you'll get the same error if the "startLoading" function is called.
Because you probably need to retain the proper context (this), what you probably need is
this.a.addEventListener("complete", this.loadingHandler.bind(this));
The .bind() method returns a function (exactly what addEventListener requires) that in turn will invoke your function such that this has the value requested.
In the code below, the pushElement method works just fine when dealing with the "words" variable, but as soon as I run the popElement method, it fails on the "this.words.length" piece with the following error: "Uncaught TypeError: Cannot read property 'length' of undefined".
Any ideas?
function AnimationStack() {
this.words = [];
}
AnimationStack.prototype.pushElement = function(element) {
this.words.push(element);
}
AnimationStack.prototype.popElement = function() {
if (this.words.length>0) {
var element = this.words.shift();
return element;
} else {
return null;
}
}
var AS = new AnimationStack();
var element = $("<div></div>");
AS.pushElement(element); // works perfect
AS.pushElement(element); // works perfect
AS.pushElement(element); // works perfect
var pop = AS.popElement(); // always fails
EDIT: The code above is perfect. It was in my actual implementation of how I was using the code above. I'm using setInterval to call popElement() which changes the scope of "this". Read the full answer here:
http://forrst.com/posts/Javascript_Array_Member_Variable_is_Undefined_wi-g6V
#Chad already found the answer, but here is the explanation.
If you call the function like this:
AS.popElement();
the popElement function runs in the context of the AS object (meaning "this" refers to AS). But if you use setInterval (or any callback-style function) like this:
setInterval(AS.popElement, 1000);
you are only passing a reference to the popElement function. So when popElement is executed 1000 milliseconds later, it is executed in the global context (meaning "this" refers to window). You would get the same error if you called:
window.popElement();
A possible alternative to avoid this is to do the following:
setInterval(function() { return AS.popElement() }, 1000);
Another option could be to use the apply or call methods to set your context explicitly:
setInterval(AS.popElement.apply(AS), 1000);
Problem & Reason
One of my team mate ended up in messy situtaion implementing function hooking in javascript. this is the actual code
function ActualMethod(){
this.doSomething = function() {
this.testMethod();
};
this.testMethod = function(){
alert("testMethod");
};
}
function ClosureTest(){
var objActual= new ActualMethod();
var closeHandler = objActual.doSomething;
closeHandler();
closeHandler.apply(objActual,arguments); //the fix i have added
this.ActualTest = function() {
alert("ActualTest");
};
}
In the above code, var closeHandler is created in the context of ClosureTest(), but it holds the handler of the ActualMethod.doSomething. Whenever calling the closeHandler() ended up in "object doesnt support this method" error.
This is because doSomething() function calls another method inside called this.testMethod();. Here this refers to the context of the caller not callee.so i assume the closeHandler is bound to the environment(ClosureTest) actually created.Even though it holds the handler to the another context, it just exposes the properties of its own context.
Solution
To avoid this i suggest to use apply to specify the conext in which it needs to execute.
closeHandler.apply(objActual,arguments);
Questions
is it perfect scenario for closures..??
What are the intersting places you have encountered closures in javascript..?
UPDATE
Yes its simple i can call the method directly. but the problem is, in a particular scenario I need to intercept the call to actuall method and run some code before that, finally execute the actual method..
say for an example, am using 3rd party aspx grid library, and all the mouseclick events are trapped by their controls. In particular group by mouse click i need to intercept the call to their ilbrary method and hook my mthod to execute instead and redirect the call to actual library method
hope this helps
Update: Because you probably left out some details in your code, it is difficult to adapt it into something workable without missing the point of your actual code. I do think I understand your underlying problem as you describe it. I hope the following helps.
Suppose the following simple example:
// Constructor function.
function Example() {
// Method:
this.method = function() {
alert("original method");
}
}
// You would use it like this:
var obj = new Example();
obj.method(); // Calls original method.
To intercept such a method call, you can do this:
function wrap(obj) {
var originalMethod = obj.method;
obj.method = function() {
alert("intercepted call");
originalMethod.apply(this, arguments);
}
return obj;
}
var obj = wrap(new Example());
obj.method(); // Calls wrapped method.
Unfortunately, because method() is defined in the constructor function, not on a prototype, you need to have an object instance to wrap the object.
Answer to original question: The doSomething() function is used as a method on objects created with ActualMethod(). You should use it as a method, not detach it and use it as a function in a different context. Why don't you just call the method directly?
function ClosureTest(){
var objActual = new ActualMethod();
// Call method directly, avoid messy apply() calls.
objActual.doSomething();
this.ActualTest = function() {
alert("ActualTest");
};
}
If you assign a method (a function on some object) to a local variable in Javascript and call it, the context will be different (the value of this changes). If you don't want it to happen, don't do it.
When I want to hook a function, I use the following Function method which is also a fine piece of Closure demonstration:
Function.prototype.wrap = function (wrapper) {
var __method = this;
return function() {
var __obj = this;
var args = [ __method.bind(__obj) ];
for(var i=0; i<arguments.length; i++) args.push(arguments[i]);
return wrapper.apply(__obj, args);
}
};
Then do something like:
ActualMethod = ActualMethod.wrap(function (proceed, option) {
// ... handle option
proceed(); // calls the wrapped function
});
proceed is bound to its initial object, so you can safely call it.