Why can't I access the xhr object from inside my onreadystatechange handler? [duplicate]
This question already has an answer here:
Why does Chrome debugger think closed local variable is undefined?
5 answers
Edit: I have removed the original code and replaced it with generalized code that anyone can run themselves to reproduce my problem:
var StripeCheckout = {
configure: function(obj){
obj.token();
}
};
StripeCheckout.configure({
token: function(token) {
var request = new XMLHttpRequest();
request.open('POST', 'http://localhost:3000/process-order');
request.setRequestHeader('Content-Type', 'application/json;charset=UTF-8');
request.onreadystatechange = function() {
debugger; // right here is the problem
};
request.send();
}
});
For me, inside that anonymous function where the debugger
statement is, request
is mysteriously not defined and attempting to access it is a ReferenceError
. That really mystifies me.
This is the weird part. If I create a throwaway variable defined at the top level, and set throwaway = request;
right after creating the request
object, then inside the onreadystatechange
handler throwaway
is defined and everything is okay, even though request
is not defined.
I just tested it, and I can also access it as this
at the point of the debugger statement, as expected. What gives? Why is request
not defined?
javascript scope xmlhttprequest
marked as duplicate by Louis
StackExchange.ready(function() {
if (StackExchange.options.isMobile) return;
$('.dupe-hammer-message-hover:not(.hover-bound)').each(function() {
var $hover = $(this).addClass('hover-bound'),
$msg = $hover.siblings('.dupe-hammer-message');
$hover.hover(
function() {
$hover.showInfoMessage('', {
messageElement: $msg.clone().show(),
transient: false,
position: { my: 'bottom left', at: 'top center', offsetTop: -7 },
dismissable: false,
relativeToBody: true
});
},
function() {
StackExchange.helpers.removeMessages();
}
);
});
});
Nov 28 '18 at 13:59
This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.
add a comment |
This question already has an answer here:
Why does Chrome debugger think closed local variable is undefined?
5 answers
Edit: I have removed the original code and replaced it with generalized code that anyone can run themselves to reproduce my problem:
var StripeCheckout = {
configure: function(obj){
obj.token();
}
};
StripeCheckout.configure({
token: function(token) {
var request = new XMLHttpRequest();
request.open('POST', 'http://localhost:3000/process-order');
request.setRequestHeader('Content-Type', 'application/json;charset=UTF-8');
request.onreadystatechange = function() {
debugger; // right here is the problem
};
request.send();
}
});
For me, inside that anonymous function where the debugger
statement is, request
is mysteriously not defined and attempting to access it is a ReferenceError
. That really mystifies me.
This is the weird part. If I create a throwaway variable defined at the top level, and set throwaway = request;
right after creating the request
object, then inside the onreadystatechange
handler throwaway
is defined and everything is okay, even though request
is not defined.
I just tested it, and I can also access it as this
at the point of the debugger statement, as expected. What gives? Why is request
not defined?
javascript scope xmlhttprequest
marked as duplicate by Louis
StackExchange.ready(function() {
if (StackExchange.options.isMobile) return;
$('.dupe-hammer-message-hover:not(.hover-bound)').each(function() {
var $hover = $(this).addClass('hover-bound'),
$msg = $hover.siblings('.dupe-hammer-message');
$hover.hover(
function() {
$hover.showInfoMessage('', {
messageElement: $msg.clone().show(),
transient: false,
position: { my: 'bottom left', at: 'top center', offsetTop: -7 },
dismissable: false,
relativeToBody: true
});
},
function() {
StackExchange.helpers.removeMessages();
}
);
});
});
Nov 28 '18 at 13:59
This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.
What happens if you replacedebugger;
withconsole.log(response);
?
– Boji
Nov 23 '18 at 14:07
Dont always trust debuggers. Trust what you know of the language. I've seen plenty of cases where for instance, the Edge debugger would lie about state.
– plalx
Nov 26 '18 at 2:44
2
Exact duplicate of Why does Chrome debugger think closed local variable is undefined?
– Bergi
Nov 26 '18 at 7:22
add a comment |
This question already has an answer here:
Why does Chrome debugger think closed local variable is undefined?
5 answers
Edit: I have removed the original code and replaced it with generalized code that anyone can run themselves to reproduce my problem:
var StripeCheckout = {
configure: function(obj){
obj.token();
}
};
StripeCheckout.configure({
token: function(token) {
var request = new XMLHttpRequest();
request.open('POST', 'http://localhost:3000/process-order');
request.setRequestHeader('Content-Type', 'application/json;charset=UTF-8');
request.onreadystatechange = function() {
debugger; // right here is the problem
};
request.send();
}
});
For me, inside that anonymous function where the debugger
statement is, request
is mysteriously not defined and attempting to access it is a ReferenceError
. That really mystifies me.
This is the weird part. If I create a throwaway variable defined at the top level, and set throwaway = request;
right after creating the request
object, then inside the onreadystatechange
handler throwaway
is defined and everything is okay, even though request
is not defined.
I just tested it, and I can also access it as this
at the point of the debugger statement, as expected. What gives? Why is request
not defined?
javascript scope xmlhttprequest
This question already has an answer here:
Why does Chrome debugger think closed local variable is undefined?
5 answers
Edit: I have removed the original code and replaced it with generalized code that anyone can run themselves to reproduce my problem:
var StripeCheckout = {
configure: function(obj){
obj.token();
}
};
StripeCheckout.configure({
token: function(token) {
var request = new XMLHttpRequest();
request.open('POST', 'http://localhost:3000/process-order');
request.setRequestHeader('Content-Type', 'application/json;charset=UTF-8');
request.onreadystatechange = function() {
debugger; // right here is the problem
};
request.send();
}
});
For me, inside that anonymous function where the debugger
statement is, request
is mysteriously not defined and attempting to access it is a ReferenceError
. That really mystifies me.
This is the weird part. If I create a throwaway variable defined at the top level, and set throwaway = request;
right after creating the request
object, then inside the onreadystatechange
handler throwaway
is defined and everything is okay, even though request
is not defined.
I just tested it, and I can also access it as this
at the point of the debugger statement, as expected. What gives? Why is request
not defined?
This question already has an answer here:
Why does Chrome debugger think closed local variable is undefined?
5 answers
javascript scope xmlhttprequest
javascript scope xmlhttprequest
edited Nov 23 '18 at 15:39
temporary_user_name
asked Nov 23 '18 at 13:59
temporary_user_nametemporary_user_name
16.7k2897162
16.7k2897162
marked as duplicate by Louis
StackExchange.ready(function() {
if (StackExchange.options.isMobile) return;
$('.dupe-hammer-message-hover:not(.hover-bound)').each(function() {
var $hover = $(this).addClass('hover-bound'),
$msg = $hover.siblings('.dupe-hammer-message');
$hover.hover(
function() {
$hover.showInfoMessage('', {
messageElement: $msg.clone().show(),
transient: false,
position: { my: 'bottom left', at: 'top center', offsetTop: -7 },
dismissable: false,
relativeToBody: true
});
},
function() {
StackExchange.helpers.removeMessages();
}
);
});
});
Nov 28 '18 at 13:59
This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.
marked as duplicate by Louis
StackExchange.ready(function() {
if (StackExchange.options.isMobile) return;
$('.dupe-hammer-message-hover:not(.hover-bound)').each(function() {
var $hover = $(this).addClass('hover-bound'),
$msg = $hover.siblings('.dupe-hammer-message');
$hover.hover(
function() {
$hover.showInfoMessage('', {
messageElement: $msg.clone().show(),
transient: false,
position: { my: 'bottom left', at: 'top center', offsetTop: -7 },
dismissable: false,
relativeToBody: true
});
},
function() {
StackExchange.helpers.removeMessages();
}
);
});
});
Nov 28 '18 at 13:59
This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.
What happens if you replacedebugger;
withconsole.log(response);
?
– Boji
Nov 23 '18 at 14:07
Dont always trust debuggers. Trust what you know of the language. I've seen plenty of cases where for instance, the Edge debugger would lie about state.
– plalx
Nov 26 '18 at 2:44
2
Exact duplicate of Why does Chrome debugger think closed local variable is undefined?
– Bergi
Nov 26 '18 at 7:22
add a comment |
What happens if you replacedebugger;
withconsole.log(response);
?
– Boji
Nov 23 '18 at 14:07
Dont always trust debuggers. Trust what you know of the language. I've seen plenty of cases where for instance, the Edge debugger would lie about state.
– plalx
Nov 26 '18 at 2:44
2
Exact duplicate of Why does Chrome debugger think closed local variable is undefined?
– Bergi
Nov 26 '18 at 7:22
What happens if you replace
debugger;
with console.log(response);
?– Boji
Nov 23 '18 at 14:07
What happens if you replace
debugger;
with console.log(response);
?– Boji
Nov 23 '18 at 14:07
Dont always trust debuggers. Trust what you know of the language. I've seen plenty of cases where for instance, the Edge debugger would lie about state.
– plalx
Nov 26 '18 at 2:44
Dont always trust debuggers. Trust what you know of the language. I've seen plenty of cases where for instance, the Edge debugger would lie about state.
– plalx
Nov 26 '18 at 2:44
2
2
Exact duplicate of Why does Chrome debugger think closed local variable is undefined?
– Bergi
Nov 26 '18 at 7:22
Exact duplicate of Why does Chrome debugger think closed local variable is undefined?
– Bergi
Nov 26 '18 at 7:22
add a comment |
2 Answers
2
active
oldest
votes
JavaScript functions are closures. They capture the variables in the surrounding scope that they need in order to work, but no more. Since you are not referencing request
in the actual code of your function, it is not captured by JavaScript because your function doesn't appear to need it. If you include code that references request
, then it will be defined:
var request = new XMLHttpRequest();
request.open('POST', 'http://localhost:3000/process-order');
request.setRequestHeader('Content-Type', 'application/json;charset=UTF-8');
request.onreadystatechange = function() {
console.log(request.toString());
debugger;
};
request.send();
If you run this snippet with your browser's developer tools window open, it will stop on the debugger
statement, and request
will be defined.
On the other hand, your original snippet may fail because request
is not referenced in the function, so the closure does not include it. By the time you try to look at the value of request
, it may have already been cleaned up.
The reason that this happens is for performance: if JavaScript functions just captured every single variable in scope, then many variables would never be released, and your web browser would use even more memory and take a performance hit due to having to keep track of all of those variables for longer.
add a comment |
The reference to request
is a reference into the execution context surrounding the inner function, which is a heap-allocated structure implementing part of the closure, and is subject to garbage collection.
As explained here, the V8 JavaScript engine (which is used by Chrome and Node.JS, among other applications, to implement JavaScript) does not create a closure if there is no reference to it. (This is an optimization.) Therefore, by the time you hit the debugger, the reference to request
has been lost, which is why you get ReferenceError
rather than undefined
. Note that the behavior is different in Safari 11, which uses JavaScriptCore from WebKit (rather than V8) to implement JavaScript.
If you add a reference to request
inside the inner function, then the closure will be created by V8 and you will have access to in inside the debugger.
Examples
Run this code in Chrome (or as I have, in Opera, which also uses V8) and you will see a Closure listed in the Scope chain.
var StripeCheckout = {
configure: function(obj) {
return obj.token();
}
};
StripeCheckout.configure({
token: function(token) {
var request = new XMLHttpRequest();
request.open('POST', 'https://jsonplaceholder.typicode.com/posts');
request.setRequestHeader('Content-Type', 'application/json;charset=UTF-8');
request.onreadystatechange = function() {
// include the console.log statement
// and everything works as expected.
console.log('req.rs:', request.readyState);
debugger; // right here is the problem
};
request.send();
}
});
Comment out the console.log
statement, which is the only reference to the closure, and the closure itself disappears (with V8).
However, when you run the same code (without the reference) in Safari, which uses JavaScriptCore from WebKit instead of V8, and the closure is still present with request
defined, and the debugger works as expected.
add a comment |
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
JavaScript functions are closures. They capture the variables in the surrounding scope that they need in order to work, but no more. Since you are not referencing request
in the actual code of your function, it is not captured by JavaScript because your function doesn't appear to need it. If you include code that references request
, then it will be defined:
var request = new XMLHttpRequest();
request.open('POST', 'http://localhost:3000/process-order');
request.setRequestHeader('Content-Type', 'application/json;charset=UTF-8');
request.onreadystatechange = function() {
console.log(request.toString());
debugger;
};
request.send();
If you run this snippet with your browser's developer tools window open, it will stop on the debugger
statement, and request
will be defined.
On the other hand, your original snippet may fail because request
is not referenced in the function, so the closure does not include it. By the time you try to look at the value of request
, it may have already been cleaned up.
The reason that this happens is for performance: if JavaScript functions just captured every single variable in scope, then many variables would never be released, and your web browser would use even more memory and take a performance hit due to having to keep track of all of those variables for longer.
add a comment |
JavaScript functions are closures. They capture the variables in the surrounding scope that they need in order to work, but no more. Since you are not referencing request
in the actual code of your function, it is not captured by JavaScript because your function doesn't appear to need it. If you include code that references request
, then it will be defined:
var request = new XMLHttpRequest();
request.open('POST', 'http://localhost:3000/process-order');
request.setRequestHeader('Content-Type', 'application/json;charset=UTF-8');
request.onreadystatechange = function() {
console.log(request.toString());
debugger;
};
request.send();
If you run this snippet with your browser's developer tools window open, it will stop on the debugger
statement, and request
will be defined.
On the other hand, your original snippet may fail because request
is not referenced in the function, so the closure does not include it. By the time you try to look at the value of request
, it may have already been cleaned up.
The reason that this happens is for performance: if JavaScript functions just captured every single variable in scope, then many variables would never be released, and your web browser would use even more memory and take a performance hit due to having to keep track of all of those variables for longer.
add a comment |
JavaScript functions are closures. They capture the variables in the surrounding scope that they need in order to work, but no more. Since you are not referencing request
in the actual code of your function, it is not captured by JavaScript because your function doesn't appear to need it. If you include code that references request
, then it will be defined:
var request = new XMLHttpRequest();
request.open('POST', 'http://localhost:3000/process-order');
request.setRequestHeader('Content-Type', 'application/json;charset=UTF-8');
request.onreadystatechange = function() {
console.log(request.toString());
debugger;
};
request.send();
If you run this snippet with your browser's developer tools window open, it will stop on the debugger
statement, and request
will be defined.
On the other hand, your original snippet may fail because request
is not referenced in the function, so the closure does not include it. By the time you try to look at the value of request
, it may have already been cleaned up.
The reason that this happens is for performance: if JavaScript functions just captured every single variable in scope, then many variables would never be released, and your web browser would use even more memory and take a performance hit due to having to keep track of all of those variables for longer.
JavaScript functions are closures. They capture the variables in the surrounding scope that they need in order to work, but no more. Since you are not referencing request
in the actual code of your function, it is not captured by JavaScript because your function doesn't appear to need it. If you include code that references request
, then it will be defined:
var request = new XMLHttpRequest();
request.open('POST', 'http://localhost:3000/process-order');
request.setRequestHeader('Content-Type', 'application/json;charset=UTF-8');
request.onreadystatechange = function() {
console.log(request.toString());
debugger;
};
request.send();
If you run this snippet with your browser's developer tools window open, it will stop on the debugger
statement, and request
will be defined.
On the other hand, your original snippet may fail because request
is not referenced in the function, so the closure does not include it. By the time you try to look at the value of request
, it may have already been cleaned up.
The reason that this happens is for performance: if JavaScript functions just captured every single variable in scope, then many variables would never be released, and your web browser would use even more memory and take a performance hit due to having to keep track of all of those variables for longer.
var request = new XMLHttpRequest();
request.open('POST', 'http://localhost:3000/process-order');
request.setRequestHeader('Content-Type', 'application/json;charset=UTF-8');
request.onreadystatechange = function() {
console.log(request.toString());
debugger;
};
request.send();
var request = new XMLHttpRequest();
request.open('POST', 'http://localhost:3000/process-order');
request.setRequestHeader('Content-Type', 'application/json;charset=UTF-8');
request.onreadystatechange = function() {
console.log(request.toString());
debugger;
};
request.send();
answered Nov 26 '18 at 2:51
laptoulaptou
1,8191021
1,8191021
add a comment |
add a comment |
The reference to request
is a reference into the execution context surrounding the inner function, which is a heap-allocated structure implementing part of the closure, and is subject to garbage collection.
As explained here, the V8 JavaScript engine (which is used by Chrome and Node.JS, among other applications, to implement JavaScript) does not create a closure if there is no reference to it. (This is an optimization.) Therefore, by the time you hit the debugger, the reference to request
has been lost, which is why you get ReferenceError
rather than undefined
. Note that the behavior is different in Safari 11, which uses JavaScriptCore from WebKit (rather than V8) to implement JavaScript.
If you add a reference to request
inside the inner function, then the closure will be created by V8 and you will have access to in inside the debugger.
Examples
Run this code in Chrome (or as I have, in Opera, which also uses V8) and you will see a Closure listed in the Scope chain.
var StripeCheckout = {
configure: function(obj) {
return obj.token();
}
};
StripeCheckout.configure({
token: function(token) {
var request = new XMLHttpRequest();
request.open('POST', 'https://jsonplaceholder.typicode.com/posts');
request.setRequestHeader('Content-Type', 'application/json;charset=UTF-8');
request.onreadystatechange = function() {
// include the console.log statement
// and everything works as expected.
console.log('req.rs:', request.readyState);
debugger; // right here is the problem
};
request.send();
}
});
Comment out the console.log
statement, which is the only reference to the closure, and the closure itself disappears (with V8).
However, when you run the same code (without the reference) in Safari, which uses JavaScriptCore from WebKit instead of V8, and the closure is still present with request
defined, and the debugger works as expected.
add a comment |
The reference to request
is a reference into the execution context surrounding the inner function, which is a heap-allocated structure implementing part of the closure, and is subject to garbage collection.
As explained here, the V8 JavaScript engine (which is used by Chrome and Node.JS, among other applications, to implement JavaScript) does not create a closure if there is no reference to it. (This is an optimization.) Therefore, by the time you hit the debugger, the reference to request
has been lost, which is why you get ReferenceError
rather than undefined
. Note that the behavior is different in Safari 11, which uses JavaScriptCore from WebKit (rather than V8) to implement JavaScript.
If you add a reference to request
inside the inner function, then the closure will be created by V8 and you will have access to in inside the debugger.
Examples
Run this code in Chrome (or as I have, in Opera, which also uses V8) and you will see a Closure listed in the Scope chain.
var StripeCheckout = {
configure: function(obj) {
return obj.token();
}
};
StripeCheckout.configure({
token: function(token) {
var request = new XMLHttpRequest();
request.open('POST', 'https://jsonplaceholder.typicode.com/posts');
request.setRequestHeader('Content-Type', 'application/json;charset=UTF-8');
request.onreadystatechange = function() {
// include the console.log statement
// and everything works as expected.
console.log('req.rs:', request.readyState);
debugger; // right here is the problem
};
request.send();
}
});
Comment out the console.log
statement, which is the only reference to the closure, and the closure itself disappears (with V8).
However, when you run the same code (without the reference) in Safari, which uses JavaScriptCore from WebKit instead of V8, and the closure is still present with request
defined, and the debugger works as expected.
add a comment |
The reference to request
is a reference into the execution context surrounding the inner function, which is a heap-allocated structure implementing part of the closure, and is subject to garbage collection.
As explained here, the V8 JavaScript engine (which is used by Chrome and Node.JS, among other applications, to implement JavaScript) does not create a closure if there is no reference to it. (This is an optimization.) Therefore, by the time you hit the debugger, the reference to request
has been lost, which is why you get ReferenceError
rather than undefined
. Note that the behavior is different in Safari 11, which uses JavaScriptCore from WebKit (rather than V8) to implement JavaScript.
If you add a reference to request
inside the inner function, then the closure will be created by V8 and you will have access to in inside the debugger.
Examples
Run this code in Chrome (or as I have, in Opera, which also uses V8) and you will see a Closure listed in the Scope chain.
var StripeCheckout = {
configure: function(obj) {
return obj.token();
}
};
StripeCheckout.configure({
token: function(token) {
var request = new XMLHttpRequest();
request.open('POST', 'https://jsonplaceholder.typicode.com/posts');
request.setRequestHeader('Content-Type', 'application/json;charset=UTF-8');
request.onreadystatechange = function() {
// include the console.log statement
// and everything works as expected.
console.log('req.rs:', request.readyState);
debugger; // right here is the problem
};
request.send();
}
});
Comment out the console.log
statement, which is the only reference to the closure, and the closure itself disappears (with V8).
However, when you run the same code (without the reference) in Safari, which uses JavaScriptCore from WebKit instead of V8, and the closure is still present with request
defined, and the debugger works as expected.
The reference to request
is a reference into the execution context surrounding the inner function, which is a heap-allocated structure implementing part of the closure, and is subject to garbage collection.
As explained here, the V8 JavaScript engine (which is used by Chrome and Node.JS, among other applications, to implement JavaScript) does not create a closure if there is no reference to it. (This is an optimization.) Therefore, by the time you hit the debugger, the reference to request
has been lost, which is why you get ReferenceError
rather than undefined
. Note that the behavior is different in Safari 11, which uses JavaScriptCore from WebKit (rather than V8) to implement JavaScript.
If you add a reference to request
inside the inner function, then the closure will be created by V8 and you will have access to in inside the debugger.
Examples
Run this code in Chrome (or as I have, in Opera, which also uses V8) and you will see a Closure listed in the Scope chain.
var StripeCheckout = {
configure: function(obj) {
return obj.token();
}
};
StripeCheckout.configure({
token: function(token) {
var request = new XMLHttpRequest();
request.open('POST', 'https://jsonplaceholder.typicode.com/posts');
request.setRequestHeader('Content-Type', 'application/json;charset=UTF-8');
request.onreadystatechange = function() {
// include the console.log statement
// and everything works as expected.
console.log('req.rs:', request.readyState);
debugger; // right here is the problem
};
request.send();
}
});
Comment out the console.log
statement, which is the only reference to the closure, and the closure itself disappears (with V8).
However, when you run the same code (without the reference) in Safari, which uses JavaScriptCore from WebKit instead of V8, and the closure is still present with request
defined, and the debugger works as expected.
edited Nov 27 '18 at 1:14
answered Nov 26 '18 at 2:24
Old ProOld Pro
14.7k23867
14.7k23867
add a comment |
add a comment |
What happens if you replace
debugger;
withconsole.log(response);
?– Boji
Nov 23 '18 at 14:07
Dont always trust debuggers. Trust what you know of the language. I've seen plenty of cases where for instance, the Edge debugger would lie about state.
– plalx
Nov 26 '18 at 2:44
2
Exact duplicate of Why does Chrome debugger think closed local variable is undefined?
– Bergi
Nov 26 '18 at 7:22