我的html包含两个彼此重叠的表单,一个用作添加表单,另一个用作编辑表单。我使用jQuery用以下代码显示和隐藏它们:
var editForm = $("#edit-form");
var addForm = $("#add-form");
var showEditForm = function() {
editForm.fadeIn(function() {
addForm.fadeOut();
});
};
var showAddForm = function() {
editForm.fadeOut(function() {
addForm.fadeIn();
});
};
我想让代码更紧凑,所以我直接在fadeOut()
回调上设置fadeOut()
调用,方法如下:
var showEditForm = function() {
editForm.fadeIn(addForm.fadeOut);
};
var showAddForm = function() {
editForm.fadeOut(addForm.fadeIn);
};
但这产生了以下错误Uncaught TypeError: Failed to execute 'animate' on 'Element': Valid arities are: [1], but 4 arguments provided.
,但为什么不起作用?
答案 0 :(得分:8)
这是因为将一个函数作为一个对象的属性调用是一种特殊的语法,它以对象作为上下文来调用该函数。
当你调用这样的函数时:
obj.func();
然后this
将成为函数内obj
的引用。
如果您获得对该函数的引用,然后调用它:
var f = obj.func;
f();
然后this
将引用全局上下文,即window
对象。
使用editForm.fadeIn(addForm.fadeOut);
,您可以获得addForm.fadeOut
的引用并发送到fadeIn
方法。它不再与对象相关联,因此将使用全局上下文而不是对象作为上下文来调用它。
您可以使用proxy
方法将函数与对象相关联,以便使用正确的上下文调用它:
var showEditForm = function() {
editForm.fadeIn($.proxy(addForm.fadeOut, addForm));
};
var showAddForm = function() {
editForm.fadeOut($.proxy(addForm.fadeIn, addForm));
};
答案 1 :(得分:3)
我怀疑问题是当addForm.fadeOut
被传递给fadeIn
函数(反之亦然)时,会使用错误的参数组合调用["0", "1", "2", "3"].map(function(i) {return parseInt(i);})
。
这个陷阱的典型例子似乎是:
[1,2,3,4]
这样,按预期工作,结果为["0", "1", "2", "3"].map(parseInt);
。你可能希望你可以像上面那样缩短它,然后写
[0, NaN, NaN, NaN]
不幸的是;这评估为.map
。问题是,parseInt
调用任何函数为它提供三个参数:值,索引和数组本身,而[
parseInt("0", 0), //0, radix is ignored
parseInt("1", 1), //NaN, what is base 1?
parseInt("2", 2), //NaN, 2 isn't valid binary
parseInt("3", 3) //NaN, 3 isn't valid ternary/base-3
]
最多需要两个参数:值,但也是基数/要解析的基数。(例如,基数2将字符串解析为二进制)所以实际发生的事实上是:
while (count < 100) {
std::ostringstream name;
name << "Process" << count;
browser->add(name.str().c_str());
count++;
}
我怀疑,根据错误信息,这里发生了同样的事情。函数的“arity”是传递给它的参数的数量,因此这里的错误消息表明,只提供了一个参数,提供了4个参数。
通常,对于带有可选参数的函数,在将它们直接传递给其他函数之前需要小心,否则你无法控制它将被调用的参数。
答案 2 :(得分:2)
小提琴:http://jsfiddle.net/jmj8tLfm/
调用 addForm.fadeIn
和addForm.fadeOut
时未指定通常在您致电this
时通过的addForm.fadeIn()
上下文。请按以下方式尝试.bind()
- 正确使用此变量:
var showEditForm = function() {
editForm.fadeIn(addForm.fadeOut.bind(addForm));
};
var showAddForm = function() {
editForm.fadeOut(addForm.fadeIn.bind(addForm));
};
答案 3 :(得分:2)
如果您使用Vanilla JS编写。关于为什么您还需要在匿名函数中传递回调函数的原因,与函数调用有关。
看看这个例子:
const firstFunc = (callback) => {
setTimeout(function() {
console.log('yes');
console.log(callback())
}, 3000);
}
const secondFunc = () => console.log('great');
firstFunc(function(){
secondFunc();
});
// prints 'yes' 'great' after 3 seconds
> yes
great
在调用函数时,如果您传递不带括号的回调参数,即firstFunc(secondFunc);
,则在第一个函数内部(如上)提供的第一个函数完成调用后(如上述),将调用回调函数。调用该功能。即callback()
,()是重要部分。
尝试在第一个函数callback
中省略括号,并在不带括号firstFunction(secondFunction)
的情况下将第二个函数作为回调传递,请注意您是如何传递回调函数的,但永远不会被调用。您的console.log()应该看起来像这样。
> yes
() => console.log('great')
那为什么如此重要...
如果使用第一个代码段中的设置将函数调用作为firstFunc(secondFunc())
传递。您会注意到第二个函数先打印,然后3秒后第一个函数被调用。
> great
yes
鉴于Javascript是事件驱动的,因此可以const secondFunc = () => console.log('great');
找到第二个函数的调用,它将立即调用该函数,而无需等待第一个函数的响应。这就是()在firstFunc内调用secondFunc()时所做的。
通过传递一个匿名函数,该函数直到到达callback()调用部分时才被调用。再次使用第一个代码段中的设置,尝试。
firstFunc(function(){
secondFunc();
});
firstFunc(function(){
secondFunc();
}())
查看第二个调用如何立即调用secondFunc。发生的情况是匿名函数是一个包装程序,无法立即调用您的函数。
这为什么有用? 如果secondFunc接受回调,则在第二个函数完成执行之前,不会调用该回调函数。您需要在第二个函数中调用该回调函数。
firstFunc(function(){
secondFunc(function(){
thirdFunc();
});
});