Hi I have the following closure
function createCounter() {
var numberOfCalls = 0;
return function() {
return ++numberOfCalls;
}
}
var fn = createCounter();
fn()
fn()
And I believe I understand about scope and the fact that the inner function keep the outer function's values after the outer one has returned.
What I don't understand is why I need to create this variable
var fn = createCounter()
and then invoke the variable fn() instead of initially invoking createCounter()
I saw that createCounter() just returns 'function()' instead of what has to be '1' and I don't understand why.
Thanks for the help. Read many tutorials still having problems with understanding this.
Please note: the question's isn't about how to make the code more eloquent or better, it's about understanding of what's been done
When createCounter is called it returns another function and that returned function is not evaluated unless you do so. Remember, in JavaScript functions are objects too. They can be the return value of a function.
So when you do this:
var fn = createCounter();
fn references only the function returned by createCounterfunction and not its evaluated value.
If you need to evaluate the function returned by createCounter try something like:
createCounter()();
This evaluates the returned function.
If you call it like this it will always return the same value as it creates a new numberOfCalls variable every time you call createCounter.
In Javascript, functions are objects which can be passed to and returned by other functions, as any other objects (e.g. a string, a number...).
So doing:
function foo(arg) { /* ... */ }
var someObject = new String("Hello");
foo(someObject);
is similar as:
function foo(arg) { /* ... */ }
var someFunction = new Function("Hello", "...");
foo(someFunction);
A function may thus return another function, which can be invoked as needed.
function foo() {
return new Function(...);
}
var functionReturnedByCallingFoo = foo();
functionReturnedByCallingFoo(); // can be invoked
functionReturnedByCallingFoo(); // and again
functionReturnedByCallingFoo(); // and again
Now, functions are almost never declared using the Function constructor, but rather with constructs named "function declarations" or "function expressions" - basically, the way we have defined the function "foo" in the previous examples, with a function signature and a function body delimited by curly brackets.
In such cases, the statements inside of the function body can read and write variables declared outside of the function itself ("free variables"), and not only variables declared within the function, as per the rules of lexical scoping. This is what we call a closure.
So in your case, the createCounter() function, when invoked, defines a local variable named "numberOfCalls", then return a function - the body of which having access to that variable. Executing the returned function changes the value of the variable, at each invocation, as it would for any "global" variable (i.e. variables declared in outer scopes).
Executing the createCounter() function many times would simply, each time, recreate a new local variable "numberOfCalls", initialize it to zero, and return a new function object having access to that variable.
Related
I have a question about this code below:
function myfunc () {
return 2 + 2;
}
console.log(myfunc);
Does anyone know why, when we log 'myfunc' to the console, we get the entire function itself back? Or in other words, is 'myfunc' acting as a variable that holds the function's contents, or is it just referencing that function?
Because if I go ahead & add this to the code...
myfunc = undefined; //or any other value like myfunc = 20;
...then since myfunc's value is changed, I can no longer use it to invoke the function. So what is 'myfunc' really?
The answer is yes, a function declaration creates a symbol in the local function scope (or global scope if the declaration is in that context) that works exactly like a variable declared with var (though function declarations are hoisted above var declarations).
Now, a function expression like this:
var x = function helloWorld() { return "hello world"; };
does not create a local "helloWorld" symbol (except when it does). The value of a function expression is a reference to the created function, and that can be assigned to a variable just like any other value.
Does function in javascript have global and local scope?see the code below
function doSomething()
{
function foo()
{
alert(this);
}
foo();
}
foo();
Here function foo() does not get executed. But the "this" keyword within the function points to global window object,if function doSomething() is executed.That means the function foo() is executing on the global scope .since it is executing in global scope why cant we execute the nested function directly without first executing the doSomething().
You're confusing scope and context. The first is fixed for the given function (unless it's returned by some function, effectively being injected into the outer scope), the second (which, among other things, defines what this refers to inside this function) is given to the function when it's invoked - and in fact can be changed with call and apply.
Consider this:
var someObj = function() {
var internalObj = {
nam: 'internal',
doSomething: function() {
console.log('Called from ' + this.name);
}
}
internalObj.doSomething('Internal'); // 1
var someFunc = internalObj.doSomething;
someFunc(); // 2
return {
nam: 'external',
doSomething: internalObj.doSomething
}
}
var x = new someObj();
x.doSomething(); // 3
setTimeout(x.doSomething, 1000); // 4
setTimeout(x.doSomething.bind({nam:'a new one'}), 2000); // 5
JSFiddle.
In this example we define method 'doSomething' as property of internalObj variable, which is local to this constructor function - if you try to access it outside the someObj, you'll get ReferenceError.
When method is called in the constructor function itself (1), you'll get 'Called from internal' logged - as the method's context object (this) refers to internalObj now.
When we assign this method (its reference) to another local variable and call it from there (2), 'undefined' gets logged instead. Scope obviously didn't change here, but context variable did: it refers to the global object now.
Then we return this method as a result of constructor - and things start getting far more interesting: our function is now available in the outer scope! Note, though, the difference between results of its invokations in (3) and (4): the former gives us external (as the context object here is the one that was created by the constructor), the latter, again, return us undefined even though the syntax is the same. ) It happens because functions sent into timeout and event handlers "lose" their context, in short... unless we fix it with Function.prototype.bind method, like in (5).
JavaScript has function level scope.
Any function declaration will be scoped to its nearest containing function automatically.
Function expressions just return a value (that is a function) so you can scope them in any way you choose.
That means the function foo() is executing on the global scope
You are confusing scope and context.
Scope is determined by where a variable is declared (with var or a special rule like "function declarations are scoped"). It effects where a variable is visible.
Context is determined by how a function is called. It effects what the value of this is.
The two are not connected.
The Facts
Function('return this')() always returns the global (window) object. Function.bind({})('return this')() returns the global object too.
My Goals
I want to create a variation of Function. The anonymous functions returned by calling that variation of Function should always use myObj as this.
If JavaScript wouldn't behave in that special way (see The Facts), I would do the following:
var myFun = Function.bind(myObj);
myFun is the object that I want to own. Now I would be able to do the following:
console.assert(myObj === myFun('return this')());
My Questions
Why is Function returning global, even after .bind()ing it to another object?
Is there a workaround? How can I bind Function to another object?
Thanks.
You are essentially doing this:
Function.call({}, 'return this;')();
The Function function is executed in the context of a new anonymous object. Doing this does not affect the context of the functions generated by Function. It turns out that Function doesn't care what context it runs in -- it always produces functions that have the default global context.
If you want to specify the context of the functions generated by Function, you want to wrap Function like this:
// give our vars privacy in a closure
(function() {
// store old Function
var oldFunc = Function;
// redefine Function to be a wrapper around the real Function
// which takes an additional `context` argument
Function = function(ftext, context) {
return oldFunc(ftext).bind(context);
}
}());
Now you can call Function('return this', myObj)(); and it will return myObj.
Or, to simply create your suggested myFun(text) syntax which passes your assert test:
var myFun = function(ftext) {
return Function(ftext).bind(myObj);
}
I don't know what exactly you are trying to achieve, but it seems that your method chaining is in the wrong order.
Function('return this').bind({})() // returns the empty Object
If you have the following code:
var global = this;
function A () {
function B () {
return this;
}
return B();
}
var C = new A();
C === global // true
Why does the this in function B refer to the global space and not the this of the object A?
The value of this is determined upon every function call. Because B is called without any context, the value of this is the global object.
It's possible to preserve this in an outer context by simply copying it:
function A() {
var x = this;
function B() {
return x;
}
return B();
}
this has nothing to do with scope, it's not a variable. It's a keyword that evaluates to the currently executing function's object context. The function's object context is determined by how you call it. It doesn't matter where or how the function is defined.
When you call a function like fn() then it is not in object context and the language wrongly attempts to work around it when it should just throw an error at the mere sight of this. This is somewhat fixed in strict mode where it would evaluate to undefined.
When you call a function as a property of some object I.E. obj.fn() then obj is bound to this for that call.
Since it would be clunky having to attach a function to some object just to get the right object context for the call, all functions inherit a .call method that allows you to specify the object context explicitly:
return B.call(this);
To accompany Pointy's correct answer:
The reasoning for this is because you can do whatever you want with functions.
You can return function B from function A, and save it as a global variable.
Or you could append function B as a method to an Object, or a dozen objects.
Or you could use it in an AJAX callback, or use it as a callback from a timer.
Because the engine doesn't know what's going to happen with function B, the language says that this refers to whatever the function is being called on, at the time it's called.
This adds a lot of dynamism to the language, but it also adds a lot of headache, if you're not sure what "this" is pointing to at any given time.
Rule of thumb:
If the function is directly attached as the method of an object, or a function is being called with .call or .apply and being fed a context, like myFunc.call(myObj), then this refers to window.
Why does calling my JavaScript function throw an error when I call it like this
wysiwyg2();
var wysiwyg2 = function()
{
alert(1);
}
but work when I do this?
wysiwyg2();
function wysiwyg2 ()
{
alert(1);
}
You need to define your function variable first, i.e.
var wysiwyg2 = function()
{
alert(1);
}
wysiwyg2();
For a good explanation of the difference, see Why can I use a function before it’s defined in Javascript?
In the first snippet, you're trying to invoke a variable before the variable is defined.
You'd get the same problem from the following code:
test.toString();
var test = new Date;
In the second snippet, you're declaring the function without assigning it to a variable, and this results in a global declaration that is usable in earlier code.
You can think of your javascript as though it's evaluated in two passes. The first pass builds all the objects and names (and remember: functions are objects), and places them "in scope", so to speak. It's kind of like a compilation step. Then the second pass executes the code.
So your second sample works because the first pass built and "scoped" the function before execution. The first sample does not work because the function object is created as part of a variable assignment, and so it's not in scope yet when you try to call it.
You mention another situation in the comments, where the function call and definition are separated into two script blocks. That doesn't work because the engine completes both steps of one block before moving on to the next, and you tried to call the function in a block that is executed before the block where it's defined. You can call function across script blocks, but not until they are defined.
In the first one, you're declaring a function and assigning it to a variable. Thus you won't be able to call it through that variable until it's actually assigned to it.
In the second, you're declaring a named function. And can call that function from wherever (as long as it's in scope).
When entering a new execution context (which is either a function call or global code), JavaScript first goes through a variable instantiation phase during which all variable declarations and function declarations within the global code or function body are examined and create as properties of the current variable object, which is effectively a collection of all the objects that are in the current scope. In particular, any function declaration such as
function wysiwyg2 ()
{
alert(1);
}
... is fully created during this phase, while any variable declaration such as
var a = 2;
... only leads to the creation of a variable called a with a value of undefined during this phase. This is also true of a variable declaration with an assignment to a function expression, such as
var wysiwyg2 = function()
{
alert(1);
}
Only the variable instantiation takes place at this point. Once this phase is complete the rest of the code (including variable assignment) is executed sequentially.