JS函数返回另一个函数

问题描述:

我想了解一些已经用于返回函数的变量。 这是示例代码JS函数返回另一个函数

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 

据我了解在绑定返回()函数不计算直到它被称为在最后一行。可以接受。所以addListener将包含一个包含'apply'的函数体。

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

+0

'F'是一个函数,它在一个名为'bind'的属性(写成对象字面值)上,它是一个返回函数的函数。 – RoToRa 2010-04-28 13:46:34

+0

对不起,错字,我会更新。当然,我会结合。 – Pablo 2010-04-28 13:51:21

的功能bind回报是closure在参数给bind功能,所以__method参数将是第一个参数bind(在你的榜样通话,这将是this.eventSource.addListener功能)。

闭包基本上是具有内在绑定数据的函数。这里有一个简单的例子:

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

通过makeAlert返回的功能“关闭了”(保留访问)范围的事情,创造了它,包括msg参数的makeAlert函数调用中。这就是为什么当我们稍后调用该函数时,即使对makeAlert的调用早已完成,它仍然有msgMore 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后,内存中的数据已经完成。这是因为它所具有的链接是一个幕后对象(松散地称为“变量对象”),它是所有参数和局部变量的容器,它们在其定义的范围内。 (在这种情况下,如果你不需要所有的数据,只需在末尾设置dataundefined。事件处理程序仍然会引用data,但该引用不再保存数组,所以数组的内存可以被回收。)

+0

所以换句话说,如果js引擎会检测将来可能使用的任何函数,它将保存后续使用的范围,所以无论何时何时调用它,该函数都可以有一定的工作范围,并且已经决定了由js设计师,范围是功能已被创建。只是想知道这个范围是不可改变的?例如,我可以在内部函数中取消定义'data'?而且,通过访问范围从其他地方取消定义'data'? – Pablo 2010-04-28 15:46:06

+0

@Michael:像Javascript中的所有对象一样,变量对象将被垃圾回收,如果没有引用它的话;该函数是一个引用变量对象的对象,它保持变量对象不被GC化。只要某些东西具有对该函数的引用,就会使该函数不被GC调用,从而使该变量对象不被GC化。你明白了。 :-)变量对象中的(属性名称)内容由代码确定;那些指向的东西可以像其他任何东西一样改变,通过给它们赋值。所以(继续) – 2010-04-28 18:45:57

+0

@Michael :(继续)所以如果你想要数据指向的数组,但只有一次,你可以在第一次使用内部函数时给它赋值undefined。或者,更有用的是,如果(例如)在外部函数中有'count'成员,则可以在内部函数中增加它。像这样的东西。 (查看我博客上的链接文章以获取更多信息。) – 2010-04-28 18:47:18

_method和args将总是被初始化,因为你定义它们,当你第一次调用

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

在那里,你会得到_method将是this.eventSource.addListener,和args会成为那两个论点。

在功能范围内,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个项目的集合复制到参数中,然后将项目从集体移动到__methodobject

由于调用bind实际上会生成另一个函数,因此新函数中的arguments实例将会不同 - 它将具有在该调用时提供的参数。来自呼叫的原始argumentsbind保存在args中,并与来自后面的函数调用的arguments组合。