Reputation: 53
If this is a duplicate, just tell me what this is a duplicate of. How would I make a js closure reused in multiple functions? It seems I can't figure it out, I might be missing something, but I either have to keep reimplementing inner function (to create closure), or put the function outside (but then, it's not closure anymore). How do I do both at the same time?
Example: So a js closure is create like this:
function a()
{
var x = "99";
var b = function()
{
//x=99
}
}
function z()
{
var x = "99";
var b = function()
{
//x=99
}
}
HOWEVER, this is NOT closure:
function bTemplate()
{
//when coming from call of b() in m, x will not be the x from function m!
}
function m()
{
var x = "99";
var b = bTemplate;
b(); //x is not the x from function m
}
function n()
{
var x = "98";
var b = bTemplate;
b(); //x is not the x from function m
}
My question is: *how to define a function from outside (to avoid repetition), AND at the same time create a closure so arguments don't have to be passed in? Maybe it's something really obvious but for some reason, cant figure it out. *
For example above, if m and n are slightly different wrapper functions, how to capture the state of both without having bTemplate implemented as inner functions in both?
Thanks!
Upvotes: 2
Views: 230
Reputation: 122429
You could exploit the this
argument that is implicitly passed to functions. But again, it is still "passing" something, even though it's not explicitly declared as a parameter.
function bTemplate()
{
// here use this.x
}
function m()
{
this.x = "99";
bTemplate.call(this);
}
function n()
{
this.x = "98";
bTemplate.call(this);
}
Upvotes: 1
Reputation: 53
I think that you all are right, I can't do both at the same time. I have to either redefine it, or pass it. I guess nothing stops me from making sure the inner functions have variables defined as properties of themselves, then passing that inner function itself to the outer template function via function call, then having the environment captured that way, if I really wanted to have multiple inner functions pass themselves to an outer, and that's probably the only way isn't it? I think I get it now. Thanks!
Example: http://jsfiddle.net/BY3Kc/3/
HTML:
<div id="a"></div>
CSS:
$("#a").css({"width":500,"height":500,"border":"3px solid"});
function outsider(obj,cb)
{
console.log(obj.o);
cb();
}
$("#a").on("click",function(){
var that = arguments.callee;
that.o = "a";
outsider(that,function(){console.log("done")});
});
$("#a").on("dblclick",function(){
var that = arguments.callee;
that.o = "b";
outsider(that,function(){console.log("done2")});
});
Upvotes: 0
Reputation: 122429
You can't. This is the gist of lexical scoping -- use of a variable refers to the variable defined in a lexically enclosing scope, i.e. a scope that physically surrounds it in the source code. Thus you can determine the variable that is referred to solely by looking at the source code.
Thus if you want to use the variable x
in the function, it must either be a parameter or local variable, or it must be defined in a lexically surrounding scope.
If you want to be able to refer to variables in the calling scope, that is called dynamic scoping. Dynamic scoping is interesting, but not intuitive. There were historically some languages that used dynamic scoping. No language in common use today uses dynamic scoping (Perl can be made to do dynamic scoping, but by default it is still lexical scoping).
Upvotes: 0
Reputation: 14282
Two possible solutions.
One. Use the controversial eval()
.
function changeX() {
x += 40;
console.log(x);
}
function a() {
var x = 7;
eval(changeX.toString());
changeX();
}
Two. Drop the love affair with closures. Just use "normal" objects in whatever flavor you prefer.
function Closure() {
this.changeX = function() {
this.x += 40;
console.log(this.x);
}
}
function a() {
Closure.apply(this);
this.x = 1;
this.changeX();
}
function b() {
Closure.apply(this);
this.x = 2;
this.changeX();
}
function c() {
this.x = 3;
this.changeX();
}
c.prototype = new Closure();
... or however you prefer to build your objects.
Bear in mind, the only distinction between a "normal" object and a closure, at least as it pertains to your question, is the presence of absence of this.
in front of your variables.
I'd personally suggest approach two: Just build objects and accustom yourself to typing this.
and that.
. eval()
gets the job done, but it's controversial and unnecessary.
Upvotes: -1
Reputation: 208425
Here is one potential approach:
function make_b(x) {
var b = function() {
//x come from argument to make_b
};
return b;
}
function a() {
var x = "99";
var b = make_b(x);
}
function z() {
var x = "99";
var b = make_b(x);
}
This allows you to define the function b
in only one place, and in both a
and z
the value of x
is accessed in without being passed into b
by using a closure. I think this fits your requirements, although it is still a little unclear why you don't want to just pass x
into b
.
Upvotes: 2
Reputation: 2875
function Wrapper(){
var x = "99";
this.bTemplate = function()
{
//has access now to x because x is closed over by wrapper function
}
this.m = function()
{
var b = bTemplate;
b(); //x is now the same x as m because it is declared in Wrapper
}
}
Upvotes: 1
Reputation: 1459
You are completely missing the point of lexical scoping.
In your example, functions a and b belong in the same scope, therefore each should have an inner scope chain completely invisible to the other. The way you are trying to do it violates how JavaScript interpreter works and therefore is impossible without inventing your own DSL or something.
You should use your second example.
Upvotes: 1
Reputation: 12985
Could you solve your problem by doing:
function cl() {
var x = 99;
var funcs = {};
funcs.a = function() {
return x;
}
funcs.b = function() {
return 2*x;
}
return funcs;
}
theFuncs = cl();
theFuncs.a();
theFuncs.b();
Upvotes: 1