Reputation: 23
So i was playing around with the concept of callbacks and i ran into a situation where I wanted to make sure i knew what i thought was happening, was actually happening.
function greet(callback) { // 'greet' function takes a callback
var greeting = "hi"; // 'greeting' variable is set in the scope
callback() // 'callback' function is invoked
}
greet(
function() {
console.log(greeting)
});
//Console logs nothing
Sorta weird, you'd expect the callback() to look in its next closest scope and figure out what greeting is. However, once i declare the greeting variable to the global execution context, greeting is logged in the console.
var greeting = 'hi' // 'greeting' variable is set in global context
function greet(callback) { // 'greet' function takes a callback
callback() // 'callback' function is invoked
}
greet(
function() {
console.log(greeting)
});
//Console logs: 'hi'
Is this because technically the callback() function that's logging the variable is actually defined in the global context and is simply being invoked inside of greet()? So it's not going to look inside of greet() first, like a normal function expression would, but right into the global context because that's where it's defined.
I just wanted to make sure i understand what's happening here and not some weird scope/block issue that i don't realize.
Upvotes: 2
Views: 2410
Reputation: 3199
Javascript uses Static Scoping
TLDR; Variables are resolved according to their location in the source code.
greeting
is only defined with the closure of the greet
function. Only code defined within the greet
function closure can see the greeting
variable.
function greet(callback) { // 'greet' function takes a callback
var greeting = "hi"; // 'greeting' variable is set in the scope
callback() // 'callback' function is invoked
}
greet(function() {
console.log(greeting)
});
Here though, greeting
is defined in a scope accessible by the nested closures of the greet
function and the anonymous function used in the console.log
call.
var greeting = 'hi' // 'greeting' variable is set in global context
function greet(callback) { // 'greet' function takes a callback
callback() // 'callback' function is invoked
}
greet(function() {
console.log(greeting)
});
NOTE: this keyword has a different set of rules.
Upvotes: 0
Reputation: 10685
You're right - the function has access to the scope which it is defined in.
Your example is effectively this (moving your callback to its own function):
var greeting = 'hi';
function greet(callback) {
callback();
}
function logGreeting() {
console.log(greeting);
}
greet(logGreeting);
As you can see, logGreeting
has access to greeting
at this point because it is defined in the same (or higher) scope.
However, when we move greeting
into the greet
function:
function greet(callback) {
var greeting = 'hi';
callback();
}
function logGreeting() {
console.log(greeting);
}
greet(logGreeting);
greeting
is no longer in the same or higher scope to logGreeting
, it's in a different scope entirely, so logGreeting
cannot look upwards through the scope in order to find greeting
.
The scope which logGreeting
has access to is the scope in which it is defined rather than which it is called, so it doesn't evaluate the scope when it's called with callback()
like you mentioned in your question.
Upvotes: 2
Reputation: 849
That's an example of lexical scope which is how JavaScript handles scope, as opposed to dynamic scope. In a nutshell lexical scope determines the context based on where things are defined and dynamic is based on where it's called.
For your first example to work like you thought would be dynamic scope.
You can read a bit more detail here in the "Lexical scope vs. dynamic scope" section.
https://en.wikipedia.org/wiki/Scope_(computer_science)
Upvotes: 2