【问题标题】:JS function returning another functionJS函数返回另一个函数
【发布时间】:2010-04-28 13:38:46
【问题描述】:

我想了解用于返回函数的变量。 这是示例代码

Prototype = {}

Prototype.F =
{
  bind: function()
  {
    var args = arguments, __method = args.shift(), object = args.shift();
    return function()
    {
        return __method.apply(object, args.concat(arguments));
    }
  }
}

function ObjectA()
{
    ...
    this.addListener = Prototype.F.bind(this.eventSource.addListener,
        this.eventSource);
    ...
}


var a = ObjectA();
a.addListener(this); // assuming 'this' here will point to some window object

据我了解,bind() 中的返回函数在最后一行调用之前不会被评估。可以接受。所以 addListener 将包含一个包含“apply”的函数体。

但是我不明白的是,当addListener被调用时,它会有什么样的参数呢?特别是 _methodargs 将始终未初始化?

【问题讨论】:

  • F 是一个函数,它在对象上(写成对象字面量),有一个名为bind 的属性,它是一个返回函数的函数。
  • 对不起,错字,我会更新。我当然要绑定。

标签: javascript function arguments


【解决方案1】:

bind 返回的函数是 closurebind 函数的参数之上的函数,因此 __method 参数将是 bind 的第一个参数(在您的示例调用中,这将是this.eventSource.addListener 函数)。

闭包基本上是本质上绑定了数据的函数。这是一个更简单的例子:

function makeAlert(msg) {
    return function() {
        alert(msg);
    }
}
var myalert = makeAlert("Hi there!");
myalert(); // Alerts "Hi there!"

makeAlert 返回的函数“关闭”(保留访问)在创建它的makeAlert 函数调用范围内的事物,包括msg 参数。这就是为什么当我们稍后调用该函数时,它仍然有msg,即使对makeAlert 的调用早已完成。 More about closures here.

关于闭包要记住的关键一点是,它们保留对定义范围内的所有内容的访问权,而不仅仅是它们显然正在使用的东西。比如:

function init() {
    var data;

    data = /* ...build some really big array of data...*/;

    document.getElementById('foo').onclick = function() {
        this.style.display = "none";
    };
}

即使事件处理程序与大数据数组无关,它仍保留对它的引用,因此在对 init 的调用完成后将数据保存在内存中。这是因为它所具有的链接指向一个幕后对象(大致称为“变量对象”),该对象是定义它的范围内的所有参数和局部变量的容器。 (在这种特殊情况下,如果您不需要所有这些数据,只需在最后将data 设置为undefined。事件处理程序仍将引用data,但该引用不包含数组,所以可以回收数组的内存。)

【讨论】:

  • 所以换句话说,如果 js 引擎会检测到任何将来可能使用的函数,它会保存作用域以供以后使用,所以每当调用它时,该函数可以具有一些作用域使用它并且由 js 设计人员决定,该范围是已创建函数的范围。只是想知道该范围是否是不可变的?例如,我可以在内部函数中取消定义 data 吗?此外,通过访问范围从其他地方取消定义data
  • @Michael:变量对象,就像 Javascript 中的所有对象一样,如果没有引用它,将被垃圾收集;该函数是一个引用变量对象的对象,它可以防止变量对象被GC'd。只要某些东西对函数有引用,就可以防止函数被 GC,从而防止变量对象被 GC。你明白了。 :-) 变量对象(中的属性名)的内容由代码确定;通过为它们分配值,可以像其他任何东西一样更改这些指向的内容。所以(续)
  • @Michael:(继续)所以如果你想要data 指向的数组,但只有一次,你可以在第一次使用内部函数时将undefined 分配给它。或者,更有用的是,如果(比如说)你在外部函数中有一个 count 成员,你可以在内部函数中增加它。像这样的东西。 (查看我博客上的链接文章了解更多信息。)
【解决方案2】:

_method 和 args 将始终被初始化,因为您在第一次调用时定义它们

this.addListener = Prototype.F.bind(this.eventSource.addListener, this.eventSource);

在那里,您将得到 _method 将是 this.eventSource.addListener,而 args 将是这两个参数。

【讨论】:

    【解决方案3】:

    在函数范围内,arguments 是一个类似数组的对象,其中包含调用函数时提供的值,无论函数定义是否定义了参数。

    所以对于这个电话:

    Prototype.F.bind(this.eventSource.addListener, this.eventSource);
    

    这导致了:

    var args = arguments, __method = args.shift(), object = args.shift();
    

    arguments 包含 2 项:this.eventSource.addListenerthis.eventSource 指向函数何时被调用。将 2 个项目的集合复制到 args,然后将项目从集合移动到 __methodobject

    由于调用bind 实际上生成了另一个函数,所以新函数中的arguments 实例会有所不同——它将具有调用时提供的参数。来自对bind 的调用的原始arguments 保存在args 中,并与来自后面的函数调用的arguments 合并。

    【讨论】:

      猜你喜欢
      • 2010-09-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-03-27
      • 2012-03-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多