没有重新定义的Javascript闭包

时间:2013-04-15 21:32:49

标签: javascript closures

如果这是重复的,请告诉我这是重复的。如何在多个函数中重用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作为内部函数实现的情况下捕获两者的状态?

谢谢!

8 个答案:

答案 0 :(得分: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,并且在az中都可以访问x的值而不会传递到b {1}}使用闭包。我认为这符合您的要求,但仍然有点不清楚为什么您不想将x传递给b

答案 1 :(得分: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
    }
}

答案 2 :(得分: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();

答案 3 :(得分:1)

你完全错过了词汇范围的观点。

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

你应该使用你的第二个例子。

答案 4 :(得分:1)

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

function bTemplate()
{
   // here use this.x
}
function m()
{
    this.x = "99";
    bTemplate.call(this);
}
function n()
{
    this.x = "98";
    bTemplate.call(this);
}

答案 5 :(得分: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")});

});

答案 6 :(得分:0)

你做不到。这是词法范围的要点 - 变量的使用是指在词法封闭范围中定义的变量,即在源代码中物理包围它的范围。因此,您可以通过查看源代码来确定仅引用的变量。

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

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

答案 7 :(得分:-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()完成工作,但这是有争议和不必要的。