1

when I'm debugging javascript I'm constantly running into situations where due to scope issues I'm not able to access variables that were suppose to be provided to me by closure.

I can traverse up a stack level to put myself in the correct scope for this case, but this is quite confusing and doesn't do the trick when you deal with promises / async calls.

I believe this is a feature where garbage collector marks and sweeps unused variables (correct me if I'm wrong).

Is there a mode that I can turn to in order to preserve closure variables (and yes I realize this could cause nothing to be garbage collected, but still useful to have when debugging and should not impact the behavior of the app)

code with this issue:

function hello(arr, foo, bar) { 
  arr.forEach(item => {
    debugger; // HERE `foo`, `arr` and `bar` are reference errors in debugger evaluation
  }); 
  return 1 
} 
hello([1,2,3], 'foo', 'bar')

------------edit-------------

UPDATED EXAMPLE

user2167582
  • 5,986
  • 13
  • 64
  • 121
  • `not able to access abc even though I am suppose to` works like a charm for me. Could you provide an example to reproduce your actual problem? `I can traverse up a stack level to put myself in the correct scope for this case, but this is quite confusing and doesn't do the trick when you deal with promises / async calls` So you have problems understanting nested scopes, and how a function can access the variables from the surrounding scope? Or is it rather a problem with time you have, and that variables may have changed their value untill the promise has beeen resolved? – Thomas Oct 18 '17 at 15:17
  • you could try turning off jit compilation, i.e. have it run in interpreter mode – the8472 Oct 18 '17 at 18:36
  • @the8472 is that what its called? – user2167582 Oct 19 '17 at 19:35
  • @Thomas its not that i dont have time to traverse up and down, but rather the current variables at a particular point aren't all accessible at debug time that would have been at run time. Traversing can only solve sync code pattern, so theres that, but most of why this bothers me is the fact that debugger doesn't reflect the true accessible scope. – user2167582 Oct 19 '17 at 19:38
  • actually, you say *"I can traverse up a stack level to put myself in the correct scope for this case, but this is quite confusing and doesn't do the trick when you deal with promises / async calls."* - so is this actually about stack walking not showing variables or about garbage collection? – the8472 Oct 19 '17 at 20:51
  • @Thomas No, there is no problem with understanding. It's just that [the JS engine optimises away unused variables from closures](https://stackoverflow.com/questions/28388530/why-does-chrome-debugger-think-closed-local-variable-is-undefined). – Bergi Oct 19 '17 at 23:02
  • "*I'm constantly running into situations*" - this is really unusual. What are you debugging where you need to know the values of variables that the compiler proofed to not be used anywhere? – Bergi Oct 19 '17 at 23:03
  • @Bergi updated example, the problem is inconvenience and uncertainty, b/c in the console it looks like this variable is unaccessible by this block while in fact it is, and sometimes you need to traverse up the stack to check the variable's value even though it should have a single closured reference. – user2167582 Nov 20 '17 at 19:54

1 Answers1

2

Assuming that this is actually about outer scopes not being captured in the first place because of optimization decisions - which means garbage collection is not involved - there are things you can try:

let singularity = null;
function blackhole(val) {
  singularity = val;
}

function someScope() {
  var abc = 'abc'
  var arr = [1...100] // pseudocode

  arr.map(n => {
      debugger;
      blackhole(abc); // forces abc to be captured
      // or ...
      eval(""); // eval leads to more conservative optimizations
    })
}

or

function someScope() {
  var abc = 'abc'
  var arr = [1...100] // pseudocode

  // normal functions are not as easily optimized as arrow functions
  arr.map(function() {
    debugger;
  })
}

or, assuming you're using firefox go to about:config and set javascript.options.baselinejit = false.

The general idea is to force the compiler to not perform optimizations that throw away unused outer scopes.

the8472
  • 40,999
  • 5
  • 70
  • 122
  • I'm quite sure that you don't need the `singularity`, just mentioning the variable `abc` as an argument to a no-op should be enough. But better be safe than sorry :-) – Bergi Oct 19 '17 at 23:07
  • Well, in java- and C-land optimizers would see straight through that and eliminate that as dead code. And as JS optimizers get better they might too. Better to be careful in that area. – the8472 Oct 20 '17 at 19:26
  • that's actually what im trying to avoid, when debugging code that might not be easy to be reran, I would expect console to reflect the correct reference of the variable without having to add a reference to it and restart the process. – user2167582 Nov 20 '17 at 19:57