以下是从this reddit post获取的一些javascript:
function Stream() {
var data = [],
listeners = [];
function push( new_data ) {
var result = data.push( new_data );
callListeners( new_data, result );
return result;
}
function addListener( listener ) {
return listeners.push( listener );
}
function callListeners( ) {
var length = listeners.length,
result = [],
action = null;
while ( length-- ) {
action = listeners[ length ];
result.push( action.apply( null, arguments) );
}
return result;
}
return {
push : push,
addListener: addListener
}
}
var foo = Stream();
foo.addListener( function( new_data ) {
alert( "added: " + new_data );
});
foo.push( "Hello World!" );
我认为在阅读this tutorial之后,我对封闭有一个微妙的把握,但我无法弄清楚这段代码的工作原理。当我试图在脑海中解析它时,我基本上陷入第6行:var result = data.push( new_data );
。
似乎(罢工 - 不知道数组有一个本地data
只是在那一点上成为一个数组data.push( foo )
没有意义。并且它不会无限地递归吗?push
方法)下一行callListener
被调用两个参数,但是函数下面没有。
如果有人有几分钟的话,你能不能抓住我的手,像我无知的傻瓜一样引导我完成这些代码?现在,我甚至不确定我是否了解目的地。
答案 0 :(得分:4)
数组是对象,它们有push()
方法。没有什么不寻常的。
callListeners()
函数没有声明任何命名参数,但JavaScript允许使用比声明参数更多的参数调用函数,并且完整的参数列表可用作特殊名称{{ 1}}。 arguments
在callListeners()
调用中使用arguments
,使用action.apply()
本身给出的相同参数列表调用action
函数。 callListeners()
的目的是用一些参数调用它,并使用这些参数调用callListeners()
数组中的所有函数。
listeners
返回的对象有两种方法Stream()
和push()
,可以“看到”相同的addListener()
和{{1即使这些数组没有存储在调用方法的对象中,也是如此。对data
的两次调用将返回两个对象,其方法会看到不同的 listeners
和Stream()
数组。
答案 1 :(得分:3)
> function Stream() {
> var data = [],
> listeners = [];
>
> function push( new_data ) {
> var result = data.push( new_data );
data
是对外部函数中数据的引用。 data.push(...)
的返回值是添加new_data
后数组的长度。
> callListeners( new_data, result );
> return result;
> }
callListeners()
是对下面用该名称声明的函数的调用。
> function addListener( listener ) {
> return listeners.push( listener );
> }
这会将listener
添加到listeners
并返回listeners
数组的新长度。
> function callListeners( ) {
> var length = listeners.length,
> result = [],
> action = null;
> while ( length-- ) {
> action = listeners[ length ];
> result.push( action.apply( null, arguments) );
> }
> return result;
> }
上面的函数使用已传递给它的参数调用listeners
数组中的所有侦听器。它虽然以相反的顺序调用它们(即最后一个被称为第一个,然后是最后一个,依此类推),这有点不寻常。
> return {
> push : push,
> addListener: addListener
> }
返回一个属性为push
的对象(其值是对使用名称 push 声明的函数的引用)和addListener
(其值是对使用名称 addListener )声明的函数
> }
>
>
> var foo = Stream();
按照惯例,名称以大写字母开头的函数是构造函数,应该使用new
运算符调用。 Stream 不是构造函数,所以应该以小写s开头。
> foo.addListener( function( new_data )
> {
> alert( "added: " + new_data ); });
调用foo.addListener
(这是对上面调用Stream()
时创建的“关闭” addListener 函数的引用)并将其传递给匿名函数。返回值没有任何作用。
> foo.push( "Hello World!" );
调用(关闭)push
函数并将其传递给字符串“Hello World!”。 push
然后调用callListeners()
,传递相同的字符串。 callListeners
然后调用侦听器数组中的每个函数(到目前为止只有一个函数,上面添加了匿名函数),并将提供给push()
的参数传递给它(即“Hello World!”)。
所以结果是一个警告“添加:Hello World!”。
如果添加另一个侦听器,则调用foo.push()
将使用提供的参数调用两个侦听器,但顺序与它们的添加顺序相反。
答案 2 :(得分:2)
首先,push
是Array类的一个方法:
通过附加给定元素并返回数组的新长度来变异数组。
所以var result = data.push( new_data );
只需将new_data
追加到data
,并将result
设置为data
中的新元素数。
callListeners
位很棘手。 action
将是一个函数,它将通过在该函数上使用apply
方法来调用(注意:函数是JavaScript中的对象)。你还会在那里看到arguments
,这是一个特殊的变量:
与传递给函数的参数对应的类数组对象。
所以,如果你想自己解压缩参数列表(比如在Perl中使用@_
,或者在C或C ++中使用变量参数列表),或者你只是计划将完整的参数列表传递给其他人想要一个数组,那么你可以使用arguments
。通常你会说:
var a = Array.prototype.slice.call(arguments);
将arguments
显式转换为真实数组。但是,在这种情况下,apply
很乐意采用原始arguments
伪数组,因此不需要“切片转换”。
答案 3 :(得分:1)
JavaScript数组具有本机push()
方法。看看这篇文章......
http://www.hunlock.com/blogs/Mastering_Javascript_Arrays
...所以代码不是递归地调用function push( new_data ){}
,而是指数组的本机push()
方法。
如果它是递归的,那么它将是var result = this.push( new_data );
,这将使它无限:)
我希望这会有所帮助 赫里斯托斯