2

如果这是重复的,请告诉我这是什么重复。如何让 js 闭包在多个函数中重用?似乎我无法弄清楚,我可能遗漏了一些东西,但我要么必须继续重新实现内部函数(以创建闭包),要么将函数放在外面(但是,它不再是闭包了)。我如何同时做这两个?

示例:所以一个 js 闭包是这样创建的:

function a()
{
    var x = "99";
    var b = function()
    {
       //x=99
    }
}

function z()
{
    var x = "99";
    var b = function()
    {
       //x=99
    }
}

但是,这不是关闭:

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
}

我的问题是: *如何从外部定义一个函数(以避免重复),同时创建一个闭包,这样就不必传入参数?也许这真的很明显,但由于某种原因,无法弄清楚。*

例如上面,如果 m 和 n 是稍微不同的包装函数,如何在不将 bTemplate 实现为两者的内部函数的情况下捕获两者的状态?

谢谢!

4

8 回答 8

2

这是一种潜在的方法:

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);
}

这允许您仅在一个地方定义函数,并且b在两个地方都可以访问的值,而无需使用闭包传入。我认为这符合您的要求,尽管您还不清楚为什么您不想只通过.azxbxb

于 2013-04-15T21:49:10.620 回答
1
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
    }
}
于 2013-04-15T21:39:24.890 回答
1

你能解决你的问题吗:

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();
于 2013-04-15T21:40:11.080 回答
1

你完全错过了词汇范围的意义。

在您的示例中,函数 a 和 b 属于同一范围,因此每个函数都应该有一个彼此完全不可见的内部范围链。您尝试这样做的方式违反了 JavaScript 解释器的工作方式,因此如果不发明自己的 DSL 或其他东西,这是不可能的。

您应该使用第二个示例。

于 2013-04-15T21:44:46.133 回答
1

您可以利用this隐式传递给函数的参数。但同样,它仍然在“传递”一些东西,即使它没有明确声明为参数。

function bTemplate()
{
   // here use this.x
}
function m()
{
    this.x = "99";
    bTemplate.call(this);
}
function n()
{
    this.x = "98";
    bTemplate.call(this);
}
于 2013-04-16T19:59:46.053 回答
0

我认为你们都说得对,我不能同时做这两件事。我必须重新定义它,或者通过它。我想没有什么能阻止我确保内部函数具有定义为自身属性的变量,然后通过函数调用将该内部函数本身传递给外部模板函数,然后以这种方式捕获环境,如果我真的想拥有多个内部函数将自己传递给外部,这可能是唯一的方法不是吗?我想我现在明白了。谢谢!

示例: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")});

});
于 2013-04-15T22:34:38.897 回答
0

你不能。这是词法作用域的要点——变量的使用是指在词法封闭作用域中定义的变量,即在源代码中物理地围绕它的作用域。因此,您可以通过查看源代码来确定单独引用的变量。

因此,如果要x在函数中使用变量,它必须是参数或局部变量,或者必须在词法范围内定义。

如果您希望能够在调用范围内引用变量,则称为动态范围。动态范围很有趣,但并不直观。历史上有些语言使用动态范围。今天常用的语言都没有使用动态作用域(Perl 可以做动态作用域,但默认情况下它仍然是词法作用域)。

于 2013-04-16T08:16:24.590 回答
-1

两种可能的解决方案。

一。使用有争议的eval().

function changeX() {
  x += 40;
  console.log(x);
}

function a() {
  var x = 7;
  eval(changeX.toString());
  changeX();
}

二。放弃与闭包的恋情。只需使用您喜欢的任何口味的“普通”对象。

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();

...或者您更喜欢构建您的对象。

请记住,“正常”对象和闭包之间的唯一区别(至少与您的问题有关)是this.变量前面是否存在缺失。

我个人建议方法二:只需构建对象并习惯于键入this.that.. eval()完成工作,但这是有争议的和不必要的。

于 2013-04-15T22:01:57.297 回答