var user = {
firstName: "Alex",
sayHi: function() {
alert(this.firstName);
}
};
setTimeout(function() {
user.sayHi(); // Alex
}, 1000);
They say that the user gets from the closure.
Do I understand correctly that the method user.sayHi wrapped in a function that is declared in the global context, and that has access to the user object? This forms a closure?
user.sayHi() is wrapped in an anonymous function which is in the global scope`. This anonymous function creates a closure, though the closure is of no consequence in this case. Since the anonymous function is in the global scope, and the user in the global scope, the anonymous function has access to the user object.
Related
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.
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.
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)
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.
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.
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.
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)
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.
I want to create a closure dynamically. See code below for explanation.
function myFunction(){
parentScopedVar(); //Would like to be able to call without using 'this'.
}
function myDynamicFunc(dynamicClosure){
//What do I need to do here to dynamically create
//a var called 'parentScopedVar' that can be referenced from myFunction?
myFunction.call(self);
}
myDynamicFunc(
{
parentScopedVar : function() { alert('Hello World'); }
});
Javascript uses lexical scope (based on where the code is declared), not dynamic scope.
If you are determined to try to do something that the language doesn't really encourage, you can force a string of code to be evaluated in your current execution context using eval(string of code here). In fact, you can do all sorts of odd things with eval(), but I'd much rather write code in a way that leverages the strengths of Javascript than to use a coding style that goes against the main design theme of the language (that's my opinion).
It's not entirely clear to me what problem you're trying to solve, but you can just pass a function as an argument and then call it via the argument from the called function.
// declare your function that takes a function reference an argument
function myFunction(callback) {
// call the function that was passed
callback();
}
function myDynamicFunc(){
// declare a local function
function myAlert() {
alert('Hello World');
}
// call your other function and pass it any function reference
myFunction(myAlert);
}
This will not pass an entire execution context. To do that, you'd have to package up the context in an object and pass a reference to the object, then dereference the properties from the object. That is typically how you pass an environment in JS.
You can use locally declared functions to provide access to parent scope from a callback (again lexical scope):
// declare your function that takes a function reference an argument
function doSomething(callback) {
// call the function that was passed
callback();
}
function myFunc() {
var myLocal1 = "Hello";
var myLocal2 = "World";
function callback() {
// when this is called, it has access to the variables of the parent scope
alert(myLocal1 + " " + myLocal2);
}
doSomething(myFunc);
}
You can even use it as a lasting closure:
// declare your function that takes a function reference an argument
function doSomething(callback) {
// call the function that was passed
callback();
}
function myFunc() {
var myLocal1 = "Hello";
var myLocal2 = "World";
function callback() {
// when this is called, it has access to the variables of the parent scope
// which are still alive in this closure even though myFunc has finished
// executing 10 minutes ago
alert(myLocal1 + " " + myLocal2);
}
// call the callback function 10 minutes from now,
// long after myFunc has finished executing
setTimeout(callback, 10 * 60 * 1000);
}
Here are some reference articles on lexical and dynamic scope in Javascript:
Is it possible to achieve dynamic scoping in JavaScript without resorting to eval?
Are variables statically or dynamically "scoped" in javascript?
What is lexical scope?
I'm using Jasmine to do unit tests and I am spying on a function:
it('should loop through all inputs', function() {
var test = function() {};
spyOn(this, 'test').andCallThrough();
formManager.eachInputs($unfoldedView, test);
expect(test).toHaveBeenCalled()
});
My problem is that the spyOn takes two parameters: (context, function). What is the context of the test function and how do I get it? It's context is the inside of this anonymous function, but I don't know how to get that. (I wrote this as the context parameter, but it's not that)
When you're in the global scope, your declared variables exist as members on the global object (either window or global). When you declare variables in a local function scope, there is no analogous "local" object. (See the Stack Overflow question "JavaScript: Reference a functions local scope as an object" for more details.)
Instead, you can make your function a method of an object and use that object as the context:
it('should loop through all inputs', function() {
var obj = { test: function() {} };
spyOn(obj, 'test').andCallThrough();
formManager.eachInputs($unfoldedView, obj.test);
expect(obj.test).toHaveBeenCalled()
});
In the following customized class in javascript, in callback, why does this.obj have nothing but local variable obj has thing I want? Thanks.
function ClassTest(director) {
this.obj = {"test1": "test1"};
}
function test1(input, callback) {
callback("success");
}
ClassTest.prototype.test = function() {
var obj = this.obj;
test1("niuniu",function(e){
console.log(this.obj); // undefined
console.log(obj); // this one has stuff
});
}
// run
new ClassTest().test()
Because the function inside test1 is creating a new scope with different this context. Typical solutions are to bind or to cache this:
Binding:
test1("niuniu",function(e){
console.log(this.obj);
}.bind(this));
Caching:
var self = this;
test1("niuniu",function(e){
console.log(self.obj);
});
As for this line of code:
console.log(obj); // this one has stuff
The reason it works has to do with how JavaScript closure works. The code defined in your anonymous function has access to all variables in its local scope as well as variables defined in encompassing scopes and therefore obj is available. See How do JavaScript closures work? for more on closure.
The keyword this however, is a reference to the current scope. Because you are accessing this.obj from within the anonymous function, this refers to the anonymous function itself - which has no obj property defined. In the enclosing function, which is extending the ClassTest prototype, this refers to the current ClassTest object, which does have a obj property defined.