Javascript: outside variable used inside closure - javascript

I have a simple jquery popup plugin. The usage looks like this:
$("#popupContainer").popup({
onOpen: function () { },
onClose: function () { }
});
$("#popupContainer").popup("open", "/Home/PopupContent");
$("#popupContainer").popup("close");
This works good.
However, i want to pass a different onOpen callback for different url's i have. So i thought about making a wrapper over the plugin, like this:
var popupPlugin = {};
(function () {
var onOpen = null;
var onClose = null;
$("#popupContainer").popup({
onOpen: function () {
if (onOpen) {
onOpen();
}
onOpen = null;
},
onClose: function () {
if (onClose) {
onClose();
}
onClose = null;
}
});
popupPlugin.open = function (url, callback) {
onOpen = callback;
$("#popupContainer").popup("open", url);
}
popupPlugin.close = function (callback) {
onClose = callback;
$("#popupContainer").popup("close");
}
}());
// usage
popupPlugin.open("/Home/PopupContent", function () {
// specific callback
});
This works as expected (i now have different callbacks), but i am worried that i am creating memory leaks somehow.
Is the implementation of the popupPlugin wrapper good?

Related

Jasmin test if callback parameter is called

so i have a function which checks if a checksum is changed and if so it calls the callback which is provided by a parameter.
var watchFileChange = function watchFileChange(oldChecksum, callback){
// some code about checking checksum
if(oldChecksum != newChecksum){
callback()
}
}
exports.watchFileChange = watchFileChange;
my Jasmin specs looks like this.
var t = require('../server.js');
describe("watchFileChange", function() {
spyOn(t.watchFileChange, 'Callback');
var file_false = {
'foo.txt': 'd41dcccc8f00b204e9800998ecf8427e'
}
var file_true = {
'foo.txt': 'd41d8cd98f00b204e9800998ecf8427e'
}
function Callback() {
console.log("Callback Called")
}
it("Checksum is not right, it should call Callback function", function() {
watchFileChange(file_false, Callback);
expect(Callback).toHaveBeenCalled();
});
});
But it just doesn't work that way because Callback is not defined i get that. So my question is there a way to check if the by parameter provided callback is called?
You can create a fake object where you can define you callback function, and then pass it as the argument
var init = {
callback: function() {
console.log("Callback Called")
}
};
describe("watchFileChange", function() {
beforeEach(function() {
spyOn(init, 'callback');
});
//...
it("Checksum is not right, it should call Callback function", function() {
watchFileChange(file_false, init.callback);
expect(init.callback).toHaveBeenCalled();
});
});

Calling a method that calls a method every second

http://jsfiddle.net/hRksW/
function test() {
this.alerting = function () {
alert("test");
};
this.something = function () {
setInterval(function () {
this.alerting();
}, 1000);
};
}
var a = new test();
a.something();
Calling the function something() should call the function alerting() every second. This should alert 'test' every second. Why doesn't that happen and how can I make it happen? Note that I want to keep this design of calling a method in a method, if possible.
Store a reference of this in a variable and use it for method that run outside of the current context (like the setInterval does)
function test() {
var that = this;
this.alerting = function () {
alert("test");
};
this.something = function () {
setInterval(function () {
that.alerting();
}, 1000);
};
}
var a = new test();
a.something();
http://jsfiddle.net/N6hPB/
function test() {
this.alerting = function () {
alert("test");
};
this.something = function () {
setInterval(this.alerting, 1000);
};
}
var a = new test();
a.something();
Hope this helps! Here the timer is in ms.
function something(){
window.setInterval(alerting, 1000);
}
function alerting() {
alert('test');
}
Another way to do it is returning an object instead.
function test() {
var self = {
alerting : function () {
console.log("test");
},
something : function () {
setInterval(function () {
self.alerting();
}, 1000);
}
};
return self;
}
var a = new test();
a.something();
You can do it making an object with functions, and then call them without instantiating it.
var testCaller = {
alerting: function() {
alert("test")
},
something: function() {
// Store current scope
var self = this;
setInterval(function() {
self.alerting();
}, 1000);
}
}
testCaller.something();
You can try this code. I have tested it, and it works. In your code, "this" pointer points to somewhere else.
function test() {
test.prototype.alerting = function() {
alert("alert test");
};
test.prototype.something = function () {
setInterval(this.alerting, 1000);
};
}
var a = new test();
a.something();

How do you perform operations on an existing closure?

Creating the closure is easy but using it is confusing for me. Here is my closure. Once I have it I need to be able to call operations on it like doWork, calculateThis, doAnimation, etc. but there doesn't seem to be a way to access functions inside the closure.
function worker(input) {
return function () {
doWork = function () {
alert("doing work");
};
}
}
function caller() {
var myWorker = worker();
myWorker.doWork(); // this fails
}
*The question you're asking appears subjective and is likely to be closed. - Thanks again stackoverflow
I believe this is what you are asking for:
function worker(input) {
return {
doWork: function () {
alert("doing work");
},
doAnimation: function() {
alert("animating");
}
}
}
You can now call it using your code:
var myWorker = worker();
myWorker.doWork();
myWorker.doAnimation();
Note that your code is not really using closures, but this one does:
function worker(input) {
return {
doWork: function () {
alert("doing work: " + input);
},
doAnimation: function() {
alert("animating: " + input);
}
}
}
var workerA = worker('A');
var workerB = worker('B');
workerA.doWork();
workerB.doAnimation();
Can you see the difference?
You are trying to execute a method work() but in your example you return a function, not an object with a property "work".
Here's what you're probably after:
function worker(input) {
return {
work: function () {
alert("doing work");
};
}
}

Javascript Timeout Issue

I have this Javascript class:
function PageManager () {
this.timeoutHandler = function () {
alert ("hello");
}
this.startTimeout = function () {
this.timeout = setTimeout ("this.timeoutHandler()", 1000);
}
}
When I call obj.startTimeout (); I get this error:
this.timeoutHandler is not a function
How do I call a class function in the timeout?
If you pass a string to setTimeout, the code is evaluated in the global scope. Always pass a function reference:
this.startTimeout = function () {
var self = this;
this.timeout = setTimeout(function() {
self.timeoutHandler();
}, 1000);
}
Or if you don't need a reference to the object inside timeoutHandler, then you can pass the function directly:
this.timeout = setTimeout(this.timeoutHandler, 1000);
The problem is that you're passing setTimeout a string. This string is eval'd, with a scope of the window. So if you were to do this:
this.timeout = setTimeout ("console.log(this);", 1000);
... with Firebug installed, you'd see that this is window, which does not have a timeoutHandler method, of course.
This is why you should never, ever pass setTimeout a string. Give it a function reference instead.
function PageManager () {
this.timeoutHandler = function () {
alert ("hello");
console.log(this);
}
this.startTimeout = function () {
this.timeout = setTimeout (this.timeoutHandler, 1000);
}
}
obj = new PageManager ();
obj.startTimeout();
When you execute this code, you'll have the scope you're expecing.

What's the jQuery equivalent to this, and what does it do?

I'm converting some javascript to jQuery from ExtJS and I don't know what this does so I'm not sure what it converts to...
hideTimeout = setTimeout(this.hideAll.createDelegate(this), delay);
delay = 200
What I'm not sure about is the createDelegate(this)...
update
All the JS is...
Menu.prototype = {
init: function () {
var that = this;
this.ui.link.bind("mouseover", function (e) {
that.show();
});
this.ui.link.bind("mouseout", function (e) {
that.hide();
});
var subOptions = $("li", this.ui.parent);
$.each(subOptions, function (el) {
el = $(el);
el.bind("mouseover", that.cancelTimeout, this);
el.bind("mouseout", that.hide, this);
});
},
hideAll: function () {
$("#hd .nav ul ul").hide();
},
show: function () {
this.hideAll();
this.cancelTimeout();
showTimeout = setTimeout((function () {
this.el.show();
}).createDelegate(this), delay);
},
hide: function () {
this.cancelTimeout();
hideTimeout = setTimeout(this.hideAll.createDelegate(this), delay);
},
cancelTimeout: function () {
clearTimeout(hideTimeout);
clearTimeout(showTimeout);
}
};
Because you're in a setTimeout, this will represent the window object.
I don't know ExtJS, but it appears to be creating a delegate handler on the window.
Probably best to reference the ExtJS docs. According to the docs for createDelegate:
Creates a delegate (callback) that sets the scope to obj. Call directly on any function. Example: this.myFunction.cre...
EDIT: I believe it would be called like this:
hideTimeout = setTimeout($.proxy( this.hideAll, this), delay);
It will ensure that when hideAll is called, it will be called in its current context.
You can do the same thing for the anonymous function passed to setTimeout in show:
showTimeout = setTimeout($.proxy(function () {
this.el.show();
}, this), delay);
You can accomplish the same thing with jQuery like so:
hideTimeout = setTimeout(jQuery.proxy(this, "hideAll"), delay);
EDIT: Since the method hideAll doesn't contain a reference to this, you can accomplish this even more simply:
hideTimeout = setTimeout(this.hideAll, delay);

Categories

Resources