Ваш код должен быть чем-то вроде этого:
function foo() {
var httpRequest = new XMLHttpRequest();
httpRequest.open('GET', "/echo/json");
httpRequest.send();
return httpRequest.responseText;
}
var result = foo(); // always ends up being 'undefined'
Феликс Клинг отлично справился с написанием ответа для людей, использующих jQuery для AJAX, я решил предоставить альтернативу для людей, которые этого не делают.
( Примечание. используя новый API fetch
, угловые или обещания, я добавил еще один ответ ниже )
Это краткое резюме «Объяснение проблемы» из другого ответа, если вы не уверены, прочитав это, прочитайте это.
A в AJAX означает асинхронность. Это означает, что отправка запроса (или, скорее, получение ответа) вынимается из обычного потока выполнения. В вашем примере .send
немедленно возвращается, а следующий оператор return result;
выполняется до того, как функция, которую вы передали, когда был вызван обратный вызов success
.
Это означает когда вы возвращаетесь, слушатель, который вы определили, еще не выполнил, что означает, что возвращаемое вами значение не было определено.
Вот простая аналогия
function getFive(){
var a;
setTimeout(function(){
a=5;
},10);
return a;
}
Возвращаемое значение a
- undefined
так как часть a=5
еще не выполнена. AJAX действует так, вы возвращаете значение до того, как сервер получил возможность сообщить вашему браузеру, что это за значение.
Одним из возможных решений этой проблемы является код повторно активно , сообщая вашей программе, что делать, когда расчет завершен.
function onComplete(a){ // When the code completes, do this
alert(a);
}
function getFive(whenDone){
var a;
setTimeout(function(){
a=5;
whenDone(a);
},10);
}
Это называется CPS . В основном, мы передаем getFive
действие, которое необходимо выполнить, когда оно завершается, мы сообщаем нашему кодексу, как реагировать, когда событие завершается (например, наш вызов AJAX или в этом случае время ожидания).
Использование будет:
getFive(onComplete);
Который должен предупредить «5» на экране. (Fiddle) .
Существуют два способа решения этой проблемы:
Что касается синхронного AJAX, не делайте этого! Ответ Феликса вызывает некоторые веские аргументы в пользу того, почему это плохая идея. Подводя итог, он заморозит браузер пользователя, пока сервер не вернет ответ и не создаст очень плохой пользовательский интерфейс. Вот еще краткое резюме из MDN о том, почему:
XMLHttpRequest поддерживает как синхронную, так и асинхронную связь. В общем, однако, асинхронные запросы должны быть предпочтительнее синхронных запросов по причинам производительности.
Короче говоря, синхронные запросы блокируют выполнение кода ... ... это может вызвать серьезные проблемы ...
Если вы имеете , вы можете передать флаг: Вот как это сделать:
var request = new XMLHttpRequest(); request.open('GET', 'yourURL', false); // `false` makes the request synchronous request.send(null); if (request.status === 200) {// That's HTTP for 'ok' console.log(request.responseText); }
2. Код реструктуризации
Пусть ваша функция принимает обратный вызов. В примере код
foo
может быть сделан для принятия обратного вызова. Мы сообщим нашему кодексу, как отреагировали , когдаfoo
завершает работу.Итак:
var result = foo(); // code that depends on `result` goes here
Становится:
foo(function(result) { // code that depends on `result` });
Здесь мы передали анонимную функцию, но мы могли бы так же легко передать ссылку на существующую , чтобы он выглядел следующим образом:
function myHandler(result) { // code that depends on `result` } foo(myHandler);
Для получения дополнительной информации о том, как выполняется этот вид обратного вызова, проверьте ответ Felix.
Теперь давайте определим сам foo, чтобы действовать соответственно
function foo(callback) { var httpRequest = new XMLHttpRequest(); httpRequest.onload = function(){ // when the request is loaded callback(httpRequest.responseText);// we're calling our method }; httpRequest.open('GET', "/echo/json"); httpRequest.send(); }
Теперь мы сделали нашу функцию foo принять действие, которое будет выполняться, когда AJAX завершится успешно, мы можем продолжить это, проверив, не является ли статус ответа не 200 и действует соответственно (создайте обработчик сбоя и т. д.). Эффективное решение нашей проблемы.
Если вам все еще трудно понять это , прочитайте руководство по началу работы AJAX в MDN.
Даниэль, удивительное объяснение! Несколько слов по этому и хорошему списку указателя контекста выполнения this
в случае обработчиков событий.
В двух словах this
в JavaScript указывает объект, у которого (или из контекста выполнения которого) текущая функция была запущена, и она всегда доступна только для чтения, вы все равно не можете ее установить (такая попытка закончится сообщением «Недопустимая левая сторона в присваивании».
Для обработчиков событий: встроенный обработчики событий, такие как <element onclick="foo">
, переопределяют любые другие обработчики, прикрепленные ранее и раньше, поэтому будьте осторожны, и лучше не вмешиваться в встроенное делегирование событий. И благодаря Заре Алавердян, которая вдохновила меня на этот список примеров через несогласие обсуждение:)
el.onclick = foo; // in the foo - obj
el.onclick = function () {this.style.color = '#fff';} // obj
el.onclick = function() {doSomething();} // In the doSomething -
Window
el.addEventListener('click',foo,false) // in the foo - obj
el.attachEvent('onclick, function () { // this }') // window, all the
compliance to IE :)
<button onclick="this.style.color = '#fff';"> // obj
<button onclick="foo"> // In the foo - window, but you can <button
onclick="foo(this)">
Значение «this» зависит от «контекста», в котором выполняется функция. Контекстом может быть любой объект или глобальный объект, т. Е. Окно.
Таким образом, семантика «этого» отличается от традиционных языков ООП. И это вызывает проблемы: 1. когда функция передается другой переменной (скорее всего, обратный вызов); и 2. когда замыкание вызывается из метода-члена класса.
В обоих случаях это устанавливается в окно.
Поскольку этот поток наткнулся, я собрал несколько точек для новых читателей в this
.
this
? Мы используем это подобно тому, как мы используем местоимения в естественных языках, таких как английский: «Джон работает быстро, потому что он пытается поймать поезд». Вместо этого мы могли бы написать «... Джон пытается поймать поезд ».
var person = {
firstName: "Penelope",
lastName: "Barrymore",
fullName: function () {
// We use "this" just as in the sentence above:
console.log(this.firstName + " " + this.lastName);
// We could have also written:
console.log(person.firstName + " " + person.lastName);
}
}
this
не присваивается значение, пока объект не вызовет функцию, в которой он определен. В глобальной области действия все глобальные переменные и функции определяются на объекте window
. Следовательно, this
в глобальной функции относится к (и имеет значение) глобальный объект window
.
Когда use strict
, this
в глобальном и в анонимных функциях, не связанных с каким-либо объектом, имеет значение undefined
.
Ключевое слово this
g0] наиболее непонятно , когда: 1) мы используем метод, который использует this
, 2) мы назначаем метод, который использует this
для переменной, 3) функция, которая использует this
, передается как функция обратного вызова и 4) this
используется внутри замыкания - внутренней функции. (2)
[/g10]
Определено в сценарии ECMA 6 , стрелка- функции принимают привязку this
из охватывающей (функциональной или глобальной) области.
function foo() {
// return an arrow function
return (a) => {
// `this` here is lexically inherited from `foo()`
console.log(this.a);
};
}
var obj1 = { a: 2 };
var obj2 = { a: 3 };
var bar = foo.call(obj1);
bar.call( obj2 ); // 2, not 3!
Хотя функции-стрелки предоставляют альтернативу использованию bind()
, важно отметить, что они по существу отключают традиционный механизм this
в пользу более широкого понимания лексического охвата. (1)
Ссылки:
this
- одна из неправильно понятых концепций в JavaScript, потому что она ведет себя совсем не так, как с места на место. Просто this
ссылается на «владельца» функции, которую мы сейчас выполняем.
this
помогает получить текущий объект (контекст выполнения a.k.a.), с которым мы работаем. Если вы понимаете, в каком объекте выполняется текущая функция, вы можете легко понять, что текущий this
is
var val = "window.val"
var obj = {
val: "obj.val",
innerMethod: function () {
var val = "obj.val.inner",
func = function () {
var self = this;
return self.val;
};
return func;
},
outerMethod: function(){
return this.val;
}
};
//This actually gets executed inside window object
console.log(obj.innerMethod()()); //returns window.val
//Breakdown in to 2 lines explains this in detail
var _inn = obj.innerMethod();
console.log(_inn()); //returns window.val
console.log(obj.outerMethod()); //returns obj.val
Выше мы создаем 3 переменные с одинаковым именем «val». Один в глобальном контексте, один внутри obj и другой внутри innerMethod obj. JavaScript разрешает идентификаторы в определенном контексте, поднимая цепочку областей действия из локального глобального.
Несколько мест, где this
можно дифференцировать
var status = 1;
var helper = {
status : 2,
getStatus: function () {
return this.status;
}
};
var theStatus1 = helper.getStatus(); //line1
console.log(theStatus1); //2
var theStatus2 = helper.getStatus;
console.log(theStatus2()); //1
Когда line1, JavaScript устанавливает контекст выполнения (EC) для вызова функции, устанавливая this
объекту, на который ссылается все, что было до последнего «.». поэтому в последней строке вы можете понять, что a()
был выполнен в глобальном контексте, который является window
.
this
можно использовать для ссылки на создаваемый объект
function Person(name){
this.personName = name;
this.sayHello = function(){
return "Hello " + this.personName;
}
}
var person1 = new Person('Scott');
console.log(person1.sayHello()); //Hello Scott
var person2 = new Person('Hugh');
var sayHelloP2 = person2.sayHello;
console.log(sayHelloP2()); //Hello undefined
Когда выполняется новый Person()
, создается совершенно новый объект. Вызывается Person
и его this
установлен для ссылки на этот новый объект.
function testFunc() {
this.name = "Name";
this.myCustomAttribute = "Custom Attribute";
return this;
}
var whatIsThis = testFunc();
console.log(whatIsThis); //window
var whatIsThis2 = new testFunc();
console.log(whatIsThis2); //testFunc() / object
console.log(window.myCustomAttribute); //Custom Attribute
Если мы пропустим ключевое слово new
, whatIsThis
ссылается на самый глобальный контекст, он может найти (window
)
Если обработчик события является встроенным, this
ссылается на глобальный объект
<script type="application/javascript">
function click_handler() {
alert(this); // alerts the window object
}
</script>
<button id='thebutton' onclick='click_handler()'>Click me!</button>
При добавлении обработчика событий через JavaScript, this
относится к элементу DOM, который генерирует событие.
.apply()
.call()
и .bind()
var that = this
в JavaScript «Это» - все о сфере видимости. Каждая функция имеет свою собственную область действия, и поскольку все в JS является объектом, даже функция может хранить некоторые значения в себе, используя «это». ООП 101 учит, что «это» применимо только к экземплярам объекта. Поэтому каждый раз, когда выполняет функция, новый «экземпляр» этой функции имеет новое значение «this».
Большинство людей путаются, когда пытаются использовать «это» внутри анонимных функций закрытия например:
(function(value) { this.value = value; $('.some-elements').each(function(elt){ elt.innerHTML = this.value; // uh oh!! possibly undefined }); })(2);
Итак, внутри each (), «this» не содержит «значение», которое вы ожидаете от него (от
this.value = value;над ним). Итак, чтобы справиться с этой проблемой (без каламбуры), разработчик мог:
(function(value) { var self = this; // small change self.value = value; $('.some-elements').each(function(elt){ elt.innerHTML = self.value; // phew!! == 2 }); })(2);
попробовать; вам понравится эта схема программирования
Вероятно, самая подробная и всесторонняя статья на this
такова:
Нежное объяснение ключевого слова этого «this» в JavaScript
Идея позади this
заключается в понимании того, что типы вызова функции имеют важное значение при установке значения this
.
Когда возникают проблемы с идентификацией this
, не спрашивайте себя:
Где
blockquote>this
взято из ?, но спросите себя:
Как вызывается функция ?
blockquote>arrow function (специальный случай прозрачности контекста) спросите себя:
Какое значение имеет
blockquote>this
, где определена функция стрелки ?Этот настрой правилен при работе с
this
и избавит вас от головной боли.
Здесь является одним из хороших источников this
в JavaScript
.
Вот сводка:
this
является объектом window
<script type="text/javascript">
console.log(this === window); // true
var foo = "bar";
console.log(this.foo); // "bar"
console.log(window.foo); // "bar"
В node
с использованием repl, this
- это верхнее пространство имен. Вы можете ссылаться на него как global
. >this
{ ArrayBuffer: [Function: ArrayBuffer],
Int8Array: { [Function: Int8Array] BYTES_PER_ELEMENT: 1 },
Uint8Array: { [Function: Uint8Array] BYTES_PER_ELEMENT: 1 },
...
>global === this
true
В node
, выполняемом из сценария, this
в глобальной области запускается как пустой объект. Это не то же самое, что global
\\test.js
console.log(this); \\ {}
console.log(this === global); \\ fasle
За исключением случаев обработчиков событий DOM или когда предоставляется thisArg
(см. ниже), как в узле, так и в браузере с использованием this
в функции, которая не вызывается с new
, ссылается на глобальную область ...
<script type="text/javascript">
foo = "bar";
function testThis() {
this.foo = "foo";
}
console.log(this.foo); //logs "bar"
testThis();
console.log(this.foo); //logs "foo"
</script>
Если вы используете use strict;
, в котором case this
будет undefined
<script type="text/javascript">
foo = "bar";
function testThis() {
"use strict";
this.foo = "foo";
}
console.log(this.foo); //logs "bar"
testThis(); //Uncaught TypeError: Cannot set property 'foo' of undefined
</script>
Если вы вызываете функцию с new
, this
будет новым контекстом, он не будет ссылаться на глобальный this
.
<script type="text/javascript">
foo = "bar";
function testThis() {
this.foo = "foo";
}
console.log(this.foo); //logs "bar"
new testThis();
console.log(this.foo); //logs "bar"
console.log(new testThis().foo); //logs "foo"
</script>
Функции, которые вы создаете, становятся объектами функции. Они автоматически получают специальное свойство prototype
, которое вы можете присвоить значениям. Когда вы создаете экземпляр, вызывая функцию с помощью new
, вы получаете доступ к значениям, присвоенным свойству prototype
. Вы получаете доступ к этим значениям с помощью this
.
function Thing() {
console.log(this.foo);
}
Thing.prototype.foo = "bar";
var thing = new Thing(); //logs "bar"
console.log(thing.foo); //logs "bar"
Обычно ошибка заключается в назначении массивов или объектов на prototype
. Если вы хотите, чтобы экземпляры каждого имели свои собственные массивы, создайте их в функции, а не в прототипе.
function Thing() {
this.things = [];
}
var thing1 = new Thing();
var thing2 = new Thing();
thing1.things.push("foo");
console.log(thing1.things); //logs ["foo"]
console.log(thing2.things); //logs []
Вы можете использовать this
в любой функции объекта ссылаться на другие свойства этого объекта. Это не то же самое, что и экземпляр, созданный с помощью new
.
var obj = {
foo: "bar",
logFoo: function () {
console.log(this.foo);
}
};
obj.logFoo(); //logs "bar"
В обработчике событий HTML DOM this
всегда ссылается на элемент DOM, событие было присоединено к
function Listener() {
document.getElementById("foo").addEventListener("click",
this.handleClick);
}
Listener.prototype.handleClick = function (event) {
console.log(this); //logs "<div id="foo"></div>"
}
var listener = new Listener();
document.getElementById("foo").click();
Если вы не bind
контекст
function Listener() {
document.getElementById("foo").addEventListener("click",
this.handleClick.bind(this));
}
Listener.prototype.handleClick = function (event) {
console.log(this); //logs Listener {handleClick: function}
}
var listener = new Listener();
document.getElementById("foo").click();
Внутри атрибутов HTML, в которые вы можете поместить JavaScript, this
является ссылкой на элемент.
<div id="foo" onclick="console.log(this);"></div>
<script type="text/javascript">
document.getElementById("foo").click(); //logs <div id="foo"...
</script>
Вы можете использовать eval
для доступа к this
.
function Thing () {
}
Thing.prototype.foo = "bar";
Thing.prototype.logFoo = function () {
eval("console.log(this.foo)"); //logs "bar"
}
var thing = new Thing();
thing.logFoo();
Вы можете использовать with
, чтобы добавить this
в текущую область действия, чтобы читать и записывать значения на this
, явно не ссылаясь на this
.
function Thing () {
}
Thing.prototype.foo = "bar";
Thing.prototype.logFoo = function () {
with (this) {
console.log(foo);
foo = "foo";
}
}
var thing = new Thing();
thing.logFoo(); // logs "bar"
console.log(thing.foo); // logs "foo"
jQuery во многих местах имеет this
ссылается на элемент DOM.
<div class="foo bar1"></div>
<div class="foo bar2"></div>
<script type="text/javascript">
$(".foo").each(function () {
console.log(this); //logs <div class="foo...
});
$(".foo").on("click", function () {
console.log(this); //logs <div class="foo...
});
$(".foo").each(function () {
this.click();
});
</script>
Это лучшее объяснение, которое я видел. Понимать JavaScripts это с помощью Clarity
Ссылка эта ALLWAYS означает (и содержит значение) объект - особый объект - и он обычно используется внутри функции или метода, хотя он может использоваться вне функции в глобальной области. Обратите внимание, что когда мы используем строгий режим, это содержит значение неопределенных в глобальных функциях и анонимных функциях, которые не привязаны к какому-либо объекту.
blockquote>Существуют четыре условия, в которых это может запутать:
- Когда мы передаем метод (который использует этот ) в качестве параметра, который будет использоваться в качестве функции обратного вызова.
- Другой пример, когда это неправильно понимается, - это когда мы используем внутренний метод (замыкание). Важно отметить, что закрытие не может получить доступ к переменной этой внешней функции внешней функции], используя это ключевое слово, потому что эта переменная доступна только самой функции, а не внутренними функциями.
- Используя этот , когда метод присваивается переменной. Значение этого привязано к другому объекту, если мы назначим метод, который использует это для переменной
- Используя этот при использовании bind, apply и
Он дает примеры кода, объяснения и исправления кода, которые, как я думал, очень полезны.
В псевдоклассических терминах многие лекции учат ключевое слово «this» как объект, созданный конструктором класса или объекта. Каждый раз, когда новый объект строится из класса, представьте, что под капотом создается и возвращается локальный экземпляр «этого» объекта. Я помню, как он учил так:
function Car(make, model, year) {
var this = {}; // under the hood, so to speak
this.make = make;
this.model = model;
this.year = year;
return this; // under the hood
}
var mycar = new Car('Eagle', 'Talon TSi', 1993);
// ========= under the hood
var this = {};
this.make = 'Eagle';
this.model = 'Talon TSi';
this.year = 1993;
return this;
это использование для Scope так же, как это
<script type="text/javascript" language="javascript">
$('#tbleName tbody tr').each(function{
var txt='';
txt += $(this).find("td").eq(0).text();
\\same as above but synatx different
var txt1='';
txt1+=$('#tbleName tbody tr').eq(0).text();
alert(txt1)
});
</script>
значение txt1 и txt одинаково в вышеприведенном примере $ (this) = $ ('# tbleName tbody tr') - Same
Каждая функция контекста выполнения в javascript имеет контекст контекста этот параметр , который задается:
Каким бы ни был этот контекст области видимости, ссылается на «this».
Вы можете изменить это значение для параметра этого контекста области , используя func.call
, func.apply
или func.bind
.
По умолчанию и что сбивает с толку большинство новичков, когда вызывающий вызывающий вызов вызывается после того, как событие добавлено в элемент DOM, контекст области это значение функции является элементом DOM.
jQuery делает это тривиальным для изменения с помощью jQuery.proxy.
this
в Javascript всегда ссылается на «владельца» выполняемой функции.
Если явный владелец не определен, то ссылается на самый верхний владелец - объект окна.
Итак, если бы я сделал
function someKindOfFunction() {
this.style = 'foo';
}
element.onclick = someKindOfFunction;
this
, он ссылался бы на объект элемента. Но будьте осторожны, многие люди делают эту ошибку
<element onclick="someKindOfFunction()">
В последнем случае вы просто ссылаетесь на функцию, а не передаете ее элементу. Поэтому this
будет ссылаться на объект окна.
Может ли помочь этому ? (Большая путаница «этого» в javascript исходит из того факта, что он вообще не связан с вашим объектом, а с текущей исполняемой областью - это может быть не совсем так, как это работает, но для меня это всегда так, см. статью для полного объяснения)
Трудно получить хорошее представление о JS или написать больше, чем что-либо тривиальное в нем, если вы не понимаете его полностью. Вы не можете просто позволить себе быстро окунуться :) Я думаю, что лучший способ начать работу с JS - сначала посмотреть эти видео-лекции Дугласа Крокфорда - http://yuiblog.com/crockford/ , который охватывает это и то, и все остальное о JS.
Немного информации об этом ключевом слове
Давайте перечислим ключевое слово this
на консоль в глобальной области без кода, но
console.log(this)
В Client / Browser this
] - глобальный объект, который является window
console.log(this === window) // true
и
В ключевом слове Server / Node / Javascript this
также является глобальным объектом, который является module.exports
console.log(this === module.exports) // true
console.log(this === exports) // true
Имейте в виду, что exports
- это просто ссылка на module.exports
this
Javascript: this
определяется тем, как функция вызывается не, где она была создана! this
определяется Объектом, который остается от точки. (window
в глобальном пространстве) this
относится к элементу DOM, на котором было вызвано событие. new
ключевое слово значение this
относится к вновь созданному объекту this
с помощью функций: call
, apply
, bind
let object = {
prop1: function () {console.log(this);}
}
object.prop1(); // object is left of the dot, thus this is object
const myFunction = object.prop1 // We store the function in the variable myFunction
myFunction(); // Here we are in the global space
// myFunction is a property on the global object
// Therefore it logs the window object
document.querySelector('.foo').addEventListener('click', function () {
console.log(this); // This refers to the DOM element the eventListener was invoked from
})
document.querySelector('.foo').addEventListener('click', () => {
console.log(this); // Tip, es6 arrow function don't have their own binding to the this v
}) // Therefore this will log the global object
.foo:hover {
color: red;
cursor: pointer;
}
<div class="foo">click me</div>
function Person (name) {
this.name = name;
}
const me = new Person('Willem');
// When using the new keyword the this in the constructor function will refer to the newly created object
console.log(me.name);
// Therefore, the name property was placed on the object created with new keyword.