In my top-level function, I’m importing some dependencies using require.js. And they’re there, no problem. Within this function, I define a callback function and attempt to use some of the variables imported via require.js, that is, variables within the parent closure.
And they just aren’t there, as confirmed by a breakpoint and a peek at the Chrome inspector’s Scope Variables panel.
I understand that fn.apply
and friends only set the context as far as this
goes, not that they can destroy a reference to a closure or alter the scope chain.
define([
'backbone',
'backbone.vent',
'app/utils/foo',
'app/services/intent'
], function(Backbone, Vent, Foo) {
'use strict';
// Backbone, Vent, and Foo are defined here
Vent.on('myevent', function(options) {
// Backbone is defined here, but not Vent or Foo.
});
});
How is this even possible?
And how can I fix it?
A closure is a function having access to the parent scope, even after the parent function has closed. So basically a closure is a function of another function. We can say like a child function. A closure is an inner function that has access to the outer (enclosing) function's variables—scope chain.
If JavaScript did not have closures, then more states would have to be passed between functions explicitly, making parameter lists longer and code noisier. So, if you want a function to always have access to a private piece of state, you can use a closure.
But as explained above, in JavaScript, all functions are naturally closures (there is only one exception, to be covered in The "new Function" syntax). That is: they automatically remember where they were created using a hidden [[Environment]] property, and then their code can access outer variables.
A closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment). In other words, a closure gives you access to an outer function's scope from an inner function.
I suspect that the function where you set the breakpoint contains a reference to Backbone
, but not Vent
or Foo
.
Closures are somewhat expensive on the JS runtime. It requires the engine wrap up the object in such a way that it keeps internal references to those variables so they can be resolved correctly at the time the function is executed. So for performance reasons, Chrome (and I suspect most other engines as well) has a tendency to optimize away any closure variables that aren't actually used when the script is compiled. This can lead to some confusing things when debugging, but it's to be expected.
Consider the following example (Note x
, y
, and z
are defined in the scope of the outer function, not in global scope):
window.onload = function() {
var x = 1, y = 2, z = 3;
(function() {
debugger;
x++;
})();
}
Alternate JSFiddle demonstration
If you try to output x
and y
on the console when this script hits the debugger
directive, this is what you'll see:
And if you look at the Scope Variable panel you'll see:
Why? because Chrome has determined that y
and z
are not used within the function so there's no need for the compiled code to keep a reference to the variable. If you add a reference to y
within the script, then the compiler will keep a reference to it, and the name will no longer be undefined
in the debugger.
if you use eval() inside your closure Chrome will not use any of it's performance optimizations which means you can see the value of y
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With