节点JS匿名函数和callback

有人请帮助我。 我一直在阅读大量的javascript文档和javascript的摆弄。

我能够使用这些function,但是我没有完全得到这个必要的语法爵士乐

var http = require('http'); http.createServer(function (req, res) { res.writeHead(200, {'Content-Type': 'text/plain'}); res.end('Hello World\n'); }).listen(1337, 'myhost'); console.log('Server running at http://myhost:1337/'); 

我不知道为什么它可以使用上面的匿名函数req和res。 就像他们住在http的某个地方一样。 他们没有宣布任何地方! 它们是由引用内部对象或其他东西的匿名函数中的variables名组成的。 这很疯狂。

这样的callback函数如何?

或者像

  stream.on('data', function(data){ // use data... i dont know where its coming from // or how it got there, but use it }); 

如果你可以发布一个模仿这个过程和语法的小例子,或者说明这些callback函数是如何工作的,或者我可以如何将这些未声明的variables传递给像这样的函数,我将不胜感激。

下面的答案类似的例子。

  var b = { somefunction : function( data ){ var x = 100; x = x+1; // 101 return data(x); // returns the callback function data w/ value x } }; b.somefunction(function(foo){ foo++; // 101 + 1 console.log(foo); // prints 102 }); 

主要的问题是Javascript是一种function语言,因此您可以将函数作为parameter passing给其他函数。 在其他语言中,例如,您可能已经体验过将指针或句柄传递给函数。 考虑一下你有一些math函数的简单情况:

 function add(a,b) {return (a+b)}; function subtract(a,b) {return (ab)}: 

现在我可以创build一个新的function:

 function longWayAroundTheBarn(num1,num2,theFunc) { // invoke the passed function with the passed parameters return theFunc(num1,num2); } 

并像这样调用它:

 console.log(longWayAroundTheBarn(1,2),add); > 3 

甚至像这样:

 console.log(longWayAroundTheBarn(longWayAroundTheBarn(2,2,subtract),4,add); > 4 

显然,这将是一个愚蠢的使用callback,但你可以大致想象,这种“插入”function的能力可以非常强大。

考虑如果你不能传递函数。 这可能是你实现这个的一个方法:

 function reallyLongWayAround(num1,num2,funcName) { if(funcName==='add') return add(num1 ,num2); else if (funcName === 'subtract') return subtract(num1, num2); } 

你可以想象,除了需要编写和维护的非常繁琐的代码之外,它不是那么强大,因为reallyLongWayAround函数只能调用它所知道的代码。 通过传递函数,我的longWayAroundTheBarn不关心我是否创build了新的函数并将其传递给它。 请注意,由于input较弱,因此甚至不需要关心它传递的参数。 也许你想要实现类似的东西

  function businessDaysBetween(d1,d2) { // implementation left as a reader exercise }; 

它可以很好地调用:

 longWayAroundTheBarn(new Date(2014,1,15), new Date(2014,1,22),businessDaysBetween) 

回到你提出的具体情况, reqres不是“局部variables”,正如一个答案所指出的 – 它们被称为参数或参数。 你没有把任何东西传给他们。 他们正在通过调用函数传递给你。 如果你愿意的话,你实际上可以称他们为fredbarney ,尽pipe这将是一个可怕的想法。 重点是他们将被称为填充请求和响应对象。

实际上,你甚至不必在你的函数签名中拥有这些参数,你可以像下面那样使用一个callback函数,并通过读取参数数组来使用传递给你函数的第二个参数(注意,它实际上不是一个数组,在许多方面performance相似)。 这将是一个可怕的,可怕的想法,但是,试图说明这一点。

  var http = require('http'); http.createServer(function () { arguments[1].writeHead(200, {'Content-Type': 'text/plain'}); arguments[1].end('Hello World\n'); }).listen(1337, 'myhost'); 

req和res实际上是匿名函数的局部variables。
我有一个类似于你的问题发布的代码下面的例子。

 // static class var HelperClass = { "doSomething" : function ( callback ) { // do something here, for example ajax call to a server var data = ajaxCallFromServer(); // return the data via callback callback ( data ); }; }; // you codes here calling the HelperClass // calling .doSomething method with an anonymous function callback // that expects 1 parameter. This parameter is returned by the above // code via callback ( data ). And in the anonymous function // i called it as retData, you can call it whatever you like HelperClass.doSomething( function ( retData ) { // do soemthing with your retData here }); 

问题是, http.createServer函数接受的参数不是一个variables,而是一个函数,如果这是有道理的。 在JavaScript中,你可以做到这一点。 该函数需要在其API中指定的参数。 你可以使它匿名,就像在你的例子中,或者声明如下:

 function serverFunction(req, res) { res.writeHead(200, {'Content-Type': 'text/plain'}); res.end('Hello World\n'); } var http = require('http'); http.createServer(serverFunction).listen(1337, 'myhost'); 

但最终没有关系,只是在API中指定的行为。

你应该使用文档。 因此,例如对于createServer,请按照此页面 – http://nodejs.org/api/http.html#http_http_createserver_requestlistener

http.createServer ([requestListener])#返回一个新的Web服务器对象。

requestListener是一个自动添加到“请求”事件的函数。

然后,你检查'请求'事件 –

事件: 'request' #function (request,response) {}

每次有请求时发送。 请注意,每个连接可能有多个请求(在保持连接的情况下)。 request是http.IncomingMessage的一个实例,response是http.ServerResponse的一个实例。

关于stream,完全一样。 这里的文档 – http://nodejs.org/api/stream.html#stream_writable_stream

寻找

事件:'数据'