недавно я пытаюсь снова заняться программированием после почти семилетнего перерыва. Что меня сейчас беспокоит, так это простой случай, когда функция становится «не» функцией при обратном вызове.
Вот где это происходит:
function xhrcall() {
let xhr = new XMLHttpRequest();
xhr.responseType = "json";
xhr.open("POST", "/api", true);
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhr.send("token=xxxxxxx");
xhr.onload = () => {
let x = xhr.status == 200 ? xhr.response : false; //console.info(x) gives proper response
return x;
}
}
Когда я пытаюсь объявить его в переменной или использовать в качестве обратного вызова, мне выдается Uncaught Error.
Например, если я объявлю это так
let fn = xhrcall()
console.info(fn) //will gives me undefined result
window.callback = xhrcall()
callback() //will gives uncaught error not a function
Насколько я помню, все должно быть хорошо и работать, но это не так.
Это могут быть повторяющиеся вопросы, но я надеюсь, что кто-нибудь сможет объяснить, что здесь на самом деле не так. Я пропустил область действия функции? или это проблема с возвратом x?
Спасибо.
Если вы хотите передать или назначить функцию чему-то другому, чтобы ее использовать, вам нужно убрать ()
. Итак, let fn = xhrcall;
Этот вопрос похож на: Почему мой вызов функции, который должен быть запланирован с помощью setTimeout, выполняется немедленно?.
@Pointy, как вы сказали, let fn = xhrcall()
должен присваивать любое возвращаемое значение переменной fn
, но вместо этого я использовал console.info(fn)
неопределенное значение, поэтому здесь чего-то не хватает.
Ваша функция xhrcall()
ничего не возвращает. Обратный вызов onload что-то возвращает, но это не имеет ничего общего с тем, что возвращает xhrcall()
. Оператор return
работает только для функции, которая является его прямой содержащей функцией.
@Pointy Ах... теперь, когда вы указали на это, я только что понял, что return x
находится за пределами области действия xhrcall()
, неудивительно, что он не определен. Теперь я знаю, что делать. Спасибо.
По умолчанию, если выполнение функции не заканчивается оператором return
или если после ключевого слова return
нет выражения, то значение return
равно undefined
.
xhrcall()
return
с undefined
[1]
Это значение присвоено fn
, и ни глобальное свойство undefined
, ни примитивное значение undefined
не могут быть вызваны, поэтому ваши наблюдения последовательны.
Если вам нужно значение, которое функция стрелки, назначенная xhr.onload
, будет return
, вам придется найти другой способ получить это значение, поскольку функция стрелки не будет вызываться синхронно.
Вы можете получить это значение, используя EventTarget
, которому Event
будет отправлено, когда функция стрелки, назначенная xhr.onload
, будет запущена и завершится. Event
слушатели, слушающие это EventTarget
, будут вызваны, когда это Event
будет отправлено.
Например:
const xhrApiTarget = new EventTarget()
xhr.onload = () => {
let x = xhr.status == 200 ? xhr.response : false
const apiResEvt = new Event("api-res")
apiResEvt.response = x
xhrApiTarget.dispatchEvent(apiResEvt)
}
xhrApiTarget.addEventListener("api-res", (apiResEvt) => { apiResEvt.response })
[1] Don’t confuse with the return
in the arrow function assigned to xhr.onload
.
Спасибо за ответ. Мне никогда не приходило в голову вызвать событие и вернуть значение через ответ на событие. Хотя я уже исправил свой код, используя параметр обратного вызова, я выберу здесь ваш ответ и поэкспериментирую с ним позже. Это интересно и воодушевляет меня. Спасибо.
let fn = xhrcall()
означает «вызвать функцию с именемxhrcall
и все, что она возвращает, присвоить это переменнойfn
».