Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/node.js/35.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript函数加载(通过引用?)_Javascript_Node.js_Functional Programming_Return By Reference - Fatal编程技术网

Javascript函数加载(通过引用?)

Javascript函数加载(通过引用?),javascript,node.js,functional-programming,return-by-reference,Javascript,Node.js,Functional Programming,Return By Reference,虽然我有多年编程经验(使用多种语言),但我的背景不是Javascript。此外,今天的Javascript并不是我多年前第一次使用的Javascript。它更加复杂和强大。也就是说,我正在努力理解一些功能负载动态 函数实际返回某些内容的函数调用是直观的,但Javascript似乎对函数做了一些我无法理解的事情。我可以复制/粘贴代码,也可以尝试在自己的代码中重用此模式 例如,下面的Mongoose调用查找用户模型中的所有记录,调用的结果以某种方式在传递函数的第二个参数中结束(通过引用?) 下面是在

虽然我有多年编程经验(使用多种语言),但我的背景不是Javascript。此外,今天的Javascript并不是我多年前第一次使用的Javascript。它更加复杂和强大。也就是说,我正在努力理解一些功能负载动态

函数实际返回某些内容的函数调用是直观的,但Javascript似乎对函数做了一些我无法理解的事情。我可以复制/粘贴代码,也可以尝试在自己的代码中重用此模式

例如,下面的Mongoose调用查找用户模型中的所有记录,调用的结果以某种方式在传递函数的第二个参数中结束(通过引用?)

下面是在数组上使用简单forEach的另一个示例。不知何故,forEach填充了“user”参数

users.forEach(function(user) {
        console.log(user.username, ': Admin = ', (user.admin ? 'Yes' : 'No'));
});
有人能解释一下这一点,和/或给我指一个关于如何/为什么这样做的好指南吗

我在Node.js中看到了相同的模式,这是一个绊脚石

我是否错过了一些明显的东西,或者这仅仅是函数式编程的一个特点

乔恩

你需要

基本思想是将一个函数作为参数传递给另一个函数,然后在需要时调用它

function basic( callback ){
  console.log( 'do something here' );

  var result = 'i am the result of `do something` to be past to the callback';

  // if callback exist execute it
  callback && callback( result );
}
这是javascript的核心概念之一。但是我建议您也看看异步操作,比如ajax http请求。它不是当前
ES5
规范的一部分,但是您可以找到许多用于此规范的库和文件

function get(url) {
  // Return a new promise.
  return new Promise(function(resolve, reject) {
    // Do the usual XHR stuff
    var req = new XMLHttpRequest();
    req.open('GET', url);

    req.onload = function() {
      // This is called even on 404 etc
      // so check the status
      if (req.status == 200) {
        // Resolve the promise with the response text
        resolve(req.response);
      }
      else {
        // Otherwise reject with the status text
        // which will hopefully be a meaningful error
        reject(Error(req.statusText));
      }
    };

    // Handle network errors
    req.onerror = function() {
      reject(Error("Network Error"));
    };

    // Make the request
    req.send();
  });
}

// Use it!
get('story.json').then(function(response) {
  console.log("Success!", response);
}, function(error) {
  console.error("Failed!", error);
});
这就是所谓的。它有时用于封装异步行为,如您提供的Mongoose示例,但有时也可以以同步方式使用,如
.forEach
示例

要了解这是如何工作的,我们很容易就可以自己编一份表格

function forEach(xs, f)
  for (var i=0, len=xs.length; i<len; i++) {
    f(x[i]);
  }
}

forEach([1,2,3], function(x) { console.log(x); })
这里的想法是,您应该熟悉用JavaScript发送函数。您甚至可以在应用另一个函数后返回函数

function add(x) {
  return function(y) {
    return x + y;
  }
}

function map(xs, f) {
  function loop(ys, xs) {
    if (xs.length === 0)
      return ys;
    else
      return loop(ys.concat(f(xs[0])), xs.slice(1));
  }
  return loop([], xs);
}

map([1,2,3], add(10)); //=> [11,12,13]
很快,你就会沉浸在学习中,学习各种各样的新东西


功能

这些回调看起来很相似,但它们的用途完全不同。在第一个示例中,回调用于检索结果,因为
User.find
是一个异步函数。异步性质也是回调参数顺序的Nodejs约定背后的原因。回调的第一个参数总是用于错误

在第二个示例中,使用回调的主要原因是创建一个本地范围,当您想要在循环中执行一些异步操作时,这非常有用。例如:

users.forEach(function(user) {
    Model.find({},function(er,rows){
        if(er){
            return handle(er);
        }
        OtherModel.find({userid: user.id},function(er,result){
            if(er){
                return handle(er);
            }
            console.log(result);
        });
    });
});

上面的示例可能不适用于C样式循环,因为在执行
OtherModle.find
时,使用
var
定义的变量将被数组的最后一项覆盖。

在Javascript中,函数也是对象,可以存储在变量中。传递给另一个函数的函数通常称为“回调”(这在其他语言中也有使用,但我们不在此赘述)

查看for
Array.prototype.forEach
,尤其是触发回调的行,可能会有所帮助

由于Javascript函数也是对象,因此它们有自己的方法,特别是和,这些方法触发函数,甚至为该函数设置
this

function add(x) {
  return function(y) {
    return x + y;
  }
}

function map(xs, f) {
  function loop(ys, xs) {
    if (xs.length === 0)
      return ys;
    else
      return loop(ys.concat(f(xs[0])), xs.slice(1));
  }
  return loop([], xs);
}

map([1,2,3], add(10)); //=> [11,12,13]
回调示例(我知道这很愚蠢……以下是示例):

函数callIf(val,callbackFn){
//“arguments”在javascript中是特殊的,它不是数组(尽管它有一个索引选择器)。
//我可以调用数组的切片方法,将“参数”作为函数的“this”传递
var args=Array.prototype.slice.call(参数,2);
if(val){
callbackFn.apply(此参数为args);
}
}
var值=[
“跳”,
“关于”,
“流行音乐”,
“山姆”,
“我”,
“上午”
];
值。forEach(函数(val){
//注意:引用内部“log”函数而不是“console.log”,因为“console.log”要求“this”为“console”。
callIf(val.length<3,log,val+“是一个小词”);
功能日志(val){
控制台日志(val);
}
});
旁注:


如果您来自静态类型的语言背景,并且第一次遇到Javascript作为动态类型的语言,我给您的建议是:不要担心并接受Javascript带来的灵活性,但仍然保持一致性和良好的编程规则。强调简洁性和可读性。玩得开心:)

Research
javascript回调
。或者,如果您想更全面地了解该技术,这种风格没有什么新的。最早的javascript版本使用回调作为事件处理程序。感谢您对回调的评论。我非常感谢您花时间回复。我想我知道回调是如何工作的,但我看不出回调在这里的相关性。这不是一个函数在其他函数之后执行(在被调用的函数中),也不是用来驱动上下文中的顺序同步处理。我认为@naomik有一个很好的观点,我不知道CPS。见下面的评论。我现在可以看到回调的相关性了。即使承诺也会使用回调,因此您首先应该了解回调的一般概念。谢谢-也是非常有用的
forEach
与CPS没有太多关系?因此对回调的关注令人困惑。在我的问题中的forEach示例中,用户不是一个函数,而是一个对象,但它也可以是一个数字。CPS有点启发性,但是关注回调对我没有帮助。对!我明白了,我一直在混淆用户被分配了一个值,用户在回调范围内有一个值。但是回调是隐藏的,所以它不是完全隐藏的
users.forEach(function(user) {
    Model.find({},function(er,rows){
        if(er){
            return handle(er);
        }
        OtherModel.find({userid: user.id},function(er,result){
            if(er){
                return handle(er);
            }
            console.log(result);
        });
    });
});
function callIf(val, callbackFn) {
    // "arguments" is special in javascript, and it's not an array (although it does have an index selector).
    // I can call Array's slice method passing "arguments" as the "this" of the function
    var args = Array.prototype.slice.call(arguments, 2);
    if(val) {
        callbackFn.apply(this, args);
    }
}

var values = [
    "Hop",
    "on",
    "Pop",
    "Sam",
    "I",
    "Am"
];


values.forEach(function(val) {
    // note: referencing inner "log" function instead of "console.log" because "console.log" require's the "this" to be "console".

    callIf(val.length < 3, log, val + " is a small word.");

    function log(val) {
        console.log(val);
    }
});