Javascript函数加载(通过引用?)
Javascript function loading (by reference?)
虽然我有多年的编程经验(使用多种语言),但我的背景不是Javascript。此外,今天的Javascript并不是我多年前第一次使用的Javascript。它更加复杂和强大。也就是说,我正在努力理解一些功能有效载荷的动态。
函数实际返回的函数调用是直观的,但Javascript似乎对我无法理解的函数做了一些事情。我可以直接复制/粘贴代码,也可以尝试在自己的代码中重用这种模式。
例如,下面的Mongoose调用查找User模型中的所有记录,并且不知何故,调用的结果最终出现在传递函数的第二个参数中(通过引用?)。
User.find({}, function(err, users) { // Get all the users
if (err) throw err;
console.log(users); // Show the JSON Object
});
下面是另一个在数组上使用简单forEach的例子。不知怎的,forEach填充了"user"参数。
users.forEach(function(user) {
console.log(user.username, ': Admin = ', (user.admin ? 'Yes' : 'No'));
});
有人能解释一下吗,和/或给我一个关于如何/为什么这样做的好指南吗?
我在Node.js中看到过同样的模式,这有点像绊脚石。
我是否遗漏了一些显而易见的东西,或者这只是函数式编程的一个特点?
Jon
在Javascript中,函数也是对象,可以存储在变量中。传递给另一个函数的函数通常被称为"回调"(这在其他语言中也有使用,但我们不会去那里)。
查看Array.prototype.forEach
的polyfill可能会有所帮助,尤其是触发回调的行。
由于Javascript函数也是对象,它们有自己的方法,特别是调用和应用,这些方法触发函数,甚至设置该函数的this
值。
回调示例(我知道这很傻…这是小提琴):
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);
}
});
旁注:
如果你来自静态类型语言背景,并且第一次遇到Javascript作为动态类型语言,我给你的建议是:不要担心,接受Javascript带来的灵活性,但仍要保持一致性和良好的编程纪律。强调简洁性和可读性。玩得开心:)
这被称为连续传递样式。它有时用于封装异步行为,如您提供的Mongoose示例,但其他时候它可以以同步方式使用,如.forEach
示例。
要了解这是如何工作的,如果我们制作自己的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); })
因此,它的工作方式应该很容易理解:我们可以看到xs
被设置为我们的数组[1,2,3]
,我们在函数内部执行一个常规的for
循环。然后我们看到循环中的每个元素调用f
一次。
这里真正的优势在于函数是JavaScript中的一流成员,这使得可以使用更高阶的函数。这意味着.forEach
被认为是一个高阶函数,因为它接受函数作为自变量。
事实证明,forEach
可以用很多不同的方式实现。这是另一个。
forEach(xs, f) {
if (xs.length > 0) {
f(xs[0]);
forEach(xs.slice(1), f);
}
}
这里的想法是,您应该能够自如地使用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回调
基本思想是将一个函数作为参数传递给另一个函数,然后在需要时调用它
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请求)的Promises。它不是当前ES5
规范的一部分,但您可以找到许多库和polyfil。
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);
});
- 这在 Object 方法中不引用对象,而是引用函数绑定到的标记
- Javascript在引用函数到变量时等于这个
- 引用函数数组中的另一个函数
- window.load上单独的javascript文件中的引用函数
- 如何引用函数
- JavaScript:函数字典:函数可以从其字典中引用函数
- 未捕获的引用函数上的错误
- 从不同的.JS文件中引用函数中的数组
- 动态引用函数时的Javascript变量范围
- 函数作为对象中的属性:引用函数内部的其他属性
- 在Javascript中,如何引用函数范围内的变量,该变量来自在该函数中调用但在其他地方定义的函数
- 在IIFE中引用函数
- 如何从函数自己的实现中引用函数
- 是否可以从HTML文件中的特定脚本标签引用函数或对象?
- 在函数中引用函数的属性
- 在'class'在同一个类中引用函数不起作用
- 从JavaScript对象内的函数中引用函数
- JavaScript函数被事件监听器多次调用,即使我引用函数
- 在angularjs中的$scope成员函数中引用函数中的变量
- 如何用文档引用函数