If I declare a function literal:
var x = function(){
alert('hi');
};
console.log(x); // returns the function code.
However:
var x = (function(){
alert('hi');
})();
console.log(x); // returns undefined?
I don't understand why this happens. Isn't the point of writing a function as a literal is to still be able to access it by its variable reference name? I know this may be silly but I'm just learning javascript so don't judge too harshly.
Your function does not return anything, so its return value is undefined.
A self-executing function is executed and the function is not stored anywhere - only its return value survives (and any external variables the function sets/modifies).
For example, this code would be equivalent to var x = 'hi';:
var x = (function(){
return 'hi';
})();
The purpose of self-invoking functions is usually to create a new scope, e.g. when creating callback functions in a loop:
for(var i = 0; i < 5; i++) {
window.setTimeout(function(){ alert('i = ' + i); }, 1000 * i);
}
This would use the same i in all callbacks so it would alert i = 5 5 times.
for(var i = 0; i < 5; i++) {
(function(i) {
window.setTimeout(function(){ alert('i = ' + i); }, 1000 * i);
})(i);
}
By using a self-executing function we create a new scope and thus a new i in each loop.
Another use of self-executing functions is to create a new scope where certain variables are ensured to be available and set to the correct value:
(function($, window, undefined) {
// here the following always applies:
// $ === jQuery
// window === the global object [assuming the function was executed in the global scope]
// undefined is well, undefined - in some js engines someone could have redefined it
})(jQuery, this);
If you:
var foo = somefunction;
… then you assign a function to foo.
If you:
var foo = somefunction();
… then you assign the return value of a function call to foo
Your function:
function(){
alert('hi');
}
… has no return statement, so it will return undefined.
Related
I am trying to get around understanding javascript closures from a practical scenario.I know from a theoretical perspective , With the help of closures inner functions can have access to the variables in the enclosing function i.e parent function.
I have read a couple of questions on stackOverflow as well.
i am really missing the point of what is happening here?
var foo = [];
for(var i=0;i<10;i++){
foo[i] = function(){
return i;
}
}
console.log(foo[0]());
This gives me out a 10. Most of the articles say that by the time it reaches the inner anonymous function, The for loop is getting executed as a result the last value that is present in the loop which is 10 is being printed.
But i am still not able to get to the bottom of this.
On Contrary, If i use something like:
var foo = [];
for(var i=0;i<10;i++){
(function(){
var y =i;
foo[i] = function(){
return y;
}
})();
}
console.log(foo[0]());
I am getting the output.Any help would be highly appreciated.
maybe this code block helps
var foo = [];
for(var i = 0; i < 10; i++) {
foo[i] = function() {
return i; // is a reference and will always be the value, which 'i' have on function execution
}
}
// 'i' is 10 here!
console.log(foo[0]()); // executing the function will return the current value of 'i'
///////////////////////////////////////
var foo = [];
for(var i=0;i<10;i++) {
/* thats a IIFE (immediately invoked function expression) */
(function(a) { // 'a' is now a local variable
foo[a] = function() { // defines a function
return a; // is a reference to local variable 'a'
};
})(i); // <- passing the current value of i as parameter to the invoked function
}
// 'i' is 10 here
console.log(foo[0]()); // returns the reference to 'a' within the same scope, where the function was defined
In your first scenario, all of your functions added to the foo array are referencing the same var i. All functions will return whatever i was set to last, which is 10 because during the last iteration of the loop that's what it's value was set to.
In the second scenario, you are Immediately Invoking this function:
(function(){
var y =i;
foo[i] = function(){
return y;
}
})();
By immediately invoking it you are effectively locking in the local state of var y, for each iteration of the loop - it provides a unique scope for each function added to the array.
In JavaScript, functions can have properties. Like this:
var f = function(){ console.log("Hello!"); }
f.x = "Whoohoo";
How do I retrieve x from code within f() that might be called long after the variable f goes out of scope?
You could use the property accessor, like the assignment.
var f = function() { console.log("Hello! " + f.x); }
f.x = "Whoohoo";
console.log(f.x);
f();
For stable access, you could use a named function
var f = function foo() { console.log("Hello! " + foo.x); }
// ^^^ >>>>>>>>>>>>>>>>>>>>>>>>>>> ^^^
f.x = "Whoohoo";
console.log(f.x);
f();
If you need some more robust (but also more verbose):
var f = (function(){
var func = () => {
console.log(func.a)
}
return func
})()
f.a = 'Whoohoo'
// trying to break it
var a = f
f = 'somethingelse'
a()
If what you're looking for is to simply access that property from within your function f, you simply reference the function object (either by the variable name if it's a function expression, or by the function name if it's a function declaration).
For example:
var f = function(){ return f.x; };
f.x = "Whoohoo";
// f() => "Whoohoo"
var b = function(){ return f.x; ];
// b() => "Whoohoo"
However, your mention of calling f "long after the variable f goes out of scope" contradicts the lexical scoping of JavaScript. You cannot call the function f unless you do so from the same scope where the function was defined, or from a child scope in reference to where the function was defined. If you are "out of scope", invoking f will throw a reference error.
Let's get a little convoluted. f is already the name of the function by the expression that defines it. And a function is an object by definition in JS. So you can access it and it's properties (such as x) through the f keyword like f.x. Yet, since f is a function, you may use the it as a constructor too and do silly things like...
var f = function(){ console.log("Hello!"); };
f.x = "Whoohoo";
f.prototype.thingy = function(){
console.log(this.constructor.x);
};
var a = new f();
a.thingy();
... and from this point on lets get a little more convoluted. You might event do;
function F(){
F.prototype.thingy = function(){
return this.constructor.x;
};
var obj = Object.create(F.prototype);
console.log("Hello!");
return obj.thingy();
}
F.x = "Whoohoo";
console.log(F());
So you can get the value of a property of the function object F "from within itself" by taking an object instantiated by itself under a closure.
I don't know how to ask correctly what I need, so let me try..
How can I pass a current variable content (literal) to a function dinamically created?
Maybe with this following code you understand better:
function MyClass(){
for (i = 1; i <= 10; i++){
this['show' + i] = function(){
alert('You called show' + i);
};
}
}
var obj = new MyClass();
obj.show3();
What I would like to be displayed in alert is "You called show3" instead of "show11".
Thanks
Since javascript doesn't have a block scope (until let in ECMAScript 6) your original function will be bound with the same value of i.
Calling another that generate itself a new function you avoid that and you give to i different values.
function MyClass() {
for (i = 1; i <= 10; i++) {
this['show' + i] = myFunc(i);
}
}
function myFunc(i) {
return function() {
alert(i);
}
}
var obj = new MyClass();
obj.show3();
There is a mechanism called binding in JavaScript. You can bind scope and any variables to the function in order to use them inside function. Scope will define this keyword inside function. All other binded variables will be available as arguments thus i variable in this example will have not a global but local scope and have a value passed in function creation.
for (i = 1; i <= 10; i++){
this['show' + i] = function(i){
alert('You called show' + i);
}.bind(this,i);
}
Can you explain me why does the second call of fn gives an error? The code is below.
function Test(n) {
this.test = n;
var bob = function (n) {
this.test = n;
};
this.fn = function (n) {
bob(n);
console.log(this.test);
};
}
var test = new Test(5);
test.fn(1); // returns 5
test.fn(2); // returns TypeError: 'undefined' is not a function
Here's a JSfiddle that reproduces the error http://jsfiddle.net/KjkQ2/
Your bob function is called from the global scope. Thefore, this.test is pointing at a global variable named test which is overwriting the variable you created. If you run console.log(window.test), you'll what's happening.
For your code to behave as intended, you would need one of the following
function Test(n) {
this.test = n;
// If a function needs 'this' it should be attached to 'this'
this.bob = function (n) {
this.test = n;
};
this.fn = function (n) {
// and called with this.functionName
this.bob(n);
console.log(this.test);
};
}
OR
function Test(n) {
this.test = n;
var bob = function (n) {
this.test = n;
};
this.fn = function (n) {
// Make sure you call bob with the right 'this'
bob.call(this, n);
console.log(this.test);
};
}
OR closure based objects
// Just use closures instead of relying on this
function Test(n) {
var test = n;
var bob = function (n) {
test = n;
};
this.fn = function (n) {
bob(n);
console.log(test);
};
}
When calling bob(n) within .fn, it is called within the global context (window in a browser). Now, you're setting window.test = n; which basically overwrites your function test object you created earlier.
If we you write this more explicit, it becomes more obvious:
// in the global scope, `test` gets written to the `global object`
// window.test = new Test(5);
var test = new Test(5);
test.fn(1); // returns 5
test.fn(2); // returns TypeError: 'undefined' is not a function
You can "workaround" this issue by calling bob() with an explicit context, using .call() for instance:
this.fn = function (n) {
bob.call(this,n);
console.log(this.test);
};
The root of evil here is, that the value of this is dynamically assigned during run-time. Don't get me wrong, its actually a great feature of ECMAscript - it's just the problem for you here. When you call a function, "just like that", this will always reference the global object.
You want to call bob.call(this, n), not just bob(n).
When you call bob(n), the value of this is not your object, it's window. Therefore, your test variable is replaced with 1.
In jsFiddle, the code is wrapped in a function, so window.test does not exist at first.
How to pass current scope variables and functions to the anonymous function in plain Javascript or in jQuery (if it's specific for frameworks).
For example:
jQuery.extend({
someFunction: function(onSomeEvent) {
var variable = 'some text'
onSomeEvent.apply(this); // how to pass current scope variables/functions to this function?
return null;
_someMethod(arg) {
console.log(arg);
}
}
});
Should log in firebug everything from the function above:
jQuery.someFunction(function(){
console.log(this.variable); // or console.log(variable);
console.log(this._someMethod(1); // or jQuery.someFunction._someMethod(2);
});
Thanks!
Read about Scopes in JavaScript for example in "Java Script: The good parts".
In the Java Script there is only scope inside Functions.
If you specify your variable inside function with var you can't access them from outside of this function. This is way to make private variables in JavaScript.
You can use this variable, that point to current object you are in (this is not a scope itself). But! if you initiate function without new command, than this will point to outer scope (in most cases it's window object = global scope).
Example:
function foo(){
var a = 10;
}
var f = foo(); //there is nothing in f
var f = new foo(); //there is nothing in f
function bar(){
this.a = 10;
}
var b = new bar(); //b.a == 10
var b = bar(); //b.a == undefined, but a in global scope
Btw, check out syntax of apply method Mozilla docs/apply
So you can see, that fist argument is object, that will be this when your method will be called.
So consider this example:
function bar(){
console.log(this.a);
console.log(this.innerMethod(10));
}
function foo(){
this.a = 10;
this.innerMethod = function(a){
return a+10;
}
bar.apply(this);
}
var f = new foo(); // => you will get 10 and 20 in the console.
var f = foo(); // => you will still get 10 and 20 in the console. But in this case, your "this" variable //will be just a global object (window)
Maybe it's better to make
var that = this;
before calling apply method, but maybe it's not needed. not sure
So, this definitely will work:
function foo(){
console.log(this.a);
}
jQuery.extend({
somefunc: function(func){
this.a = 10;
func.apply(this);
}
});
$.somefunc(foo); //will print 10.
Before line 1:
var that = this;
Then change line 4:
onSomeEvent.apply(that);