Javascript函数加载(通过引用?)
虽然我有多年编程经验(使用多种语言),但我的背景不是Javascript。此外,今天的Javascript并不是我多年前第一次使用的Javascript。它更加复杂和强大。也就是说,我正在努力理解一些功能负载动态 函数实际返回某些内容的函数调用是直观的,但Javascript似乎对函数做了一些我无法理解的事情。我可以复制/粘贴代码,也可以尝试在自己的代码中重用此模式 例如,下面的Mongoose调用查找用户模型中的所有记录,调用的结果以某种方式在传递函数的第二个参数中结束(通过引用?) 下面是在数组上使用简单forEach的另一个示例。不知何故,forEach填充了“user”参数Javascript函数加载(通过引用?),javascript,node.js,functional-programming,return-by-reference,Javascript,Node.js,Functional Programming,Return By Reference,虽然我有多年编程经验(使用多种语言),但我的背景不是Javascript。此外,今天的Javascript并不是我多年前第一次使用的Javascript。它更加复杂和强大。也就是说,我正在努力理解一些功能负载动态 函数实际返回某些内容的函数调用是直观的,但Javascript似乎对函数做了一些我无法理解的事情。我可以复制/粘贴代码,也可以尝试在自己的代码中重用此模式 例如,下面的Mongoose调用查找用户模型中的所有记录,调用的结果以某种方式在传递函数的第二个参数中结束(通过引用?) 下面是在
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中,函数也是对象,可以存储在变量中。传递给另一个函数的函数通常称为“回调”(这在其他语言中也有使用,但我们不在此赘述)
查看forArray.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);
}
});