2015-05-03 1 views
3

Мой 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

Вы должны предоставить функцию, чтобы функция fadeout функции более высокого порядка могла ее запускать. этот ответ может варьироваться от моноды до синтаксиса – raam86

ответ

1

Я подозреваю, что проблема в том, что 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 принимает до двух аргументов: значение, но также и основание radix/base для разбора (например, radix 2, чтобы разобрать строку в двоичном виде) Так что на самом деле происходит, по существу:

[ 
    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 
] 

Я подозреваю, основываясь на сообщении об ошибке, что то же самое, что происходит здесь. «Арность» функции - это количество переданных ей аргументов, поэтому в сообщении об ошибке говорится, что было предоставлено 4 аргумента, когда ожидалось только одно.

В общем случае с функциями, которые принимают необязательные аргументы, вам нужно быть осторожными, прежде чем передавать их другим функциям напрямую, иначе вы не сможете контролировать, с какими аргументами он будет вызываться.

+0

Это действительно вызывало ошибку. Используя 'addForm.fadeOut (function() {editForm.fadeIn.apply (это, аргументы);});' выбрал ту же самую ошибку –

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)); 
}; 
2

Fiddle: 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)); 
}; 
+0

Метод ['bind'] (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind) не поддерживается во всех браузеров, поэтому я рекомендую метод ['proxy'] (http://api.jquery.com/jQuery.proxy/). – Guffa