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.
Related
Functions in javascript is also an object and can have properties. So is there any way to access its properties from inside its own function body?
like this
var f = function() {
console.log(/*some way to access f.a*/);
};
f.a = 'Test';
f(); //should log 'Test' to console
arguments.callee is the function itself and doesn't get affected by the name of the function.
var f = function() {
console.log(arguments.callee.a);
};
f.a = 'Test';
f();
The classic way to do this is to bind the function to itself, after which it can access its own properties via this:
var f = function() {
console.log(this.a); // USE "THIS" TO ACCESS PROPERTY
};
f.a = 'Test';
f = f.bind(f); // BIND TO SELF
f(); // WILL LOG 'Test' TO CONSOLE
You could just use this:
console.log(f.a);
If f is executed, f(), before f.a = 'Test'; you will get undefined in the console, since there isn't any property with name/key a be defined. After f.a = 'Test'; being executed, the name/key a will be defined on f and the corresponding value would be 'Test'. Hence, executing later on the function f, the value 'Test' would be the output to the console.
Prototypes is what you are looking for.
var F = function() {
console.log(this.a);
}
F.prototype.a = 'Test';
// instantiate new Object of class F
new F();
Hope this helps!
Here is how to implement a static variable, using the function itself as an Object:
function f()
{
if (!f.staticObj)
f.staticObj={a:3};
return f.staticObj;
} // f
console.log(f().a); // Assigns the var
console.log(f().a); // Returns the var
You can use the JavaScript Closures;
https://www.w3schools.com/js/js_function_closures.asp
const add = (function () {
let counter = 0;
return function () {counter += 1; return counter}
})();
add();
add();
add();
You can set this up using an IIFE:
var f = (function () {
function f () {
console.log(f.a);
}
f.a = 'Test';
return f;
})();
f() // logs 'Test'
f.a === 'Test' // true
Note that you don't have to use f (or even a function declaration) for this to work properly:
var f = (function () {
var _f = function () {
console.log(_f.a);
};
_f.a = 'Test'
return _f;
});
f() // logs 'Test'
f.a === 'Test' // true
Some people like to use the same variable throughout to emphasize that the inner f will eventually become the outer f, and some people prefer to distinguish each scope. Either way is fine.
I know that you can write following
var obj = {
test: 'something'
}
But in this code, the inner function does not refer to a variable, but to a function.
Is there any other way to write / call the inner function?
function outer(){
var a = "Outerfunction";
console.log(a)
innerFct: function InnerFct() {
var c = "Inner";
console.log(c)
} innerFct();
}
window.outer();
There are a couple of different things going on here.
In this code:
var obj = {
test: 'something'
}
you are using "literal object notation" to create -- well, an object with one property test and that property has a value of something
In your second case, you are creating a code block (yes, it is fun that both objects and code blocks use the same syntax {...} to define them.
Inside of a code block, the innerFct: becomes a label. Labels are used with some control flow statements to jump around. Forget about them, you really are better off not using them.
function outer(){
var a = "Outerfunction";
console.log(a)
function innerFct() {
var c = "Inner";
console.log(c)
}
innerFct();
}
outer();
or even
function outer(){
var a = "Outerfunction";
console.log(a)
var innerFct = function () {
var c = "Inner";
console.log(c)
}
innerFct();
}
outer();
You are confusing functions with objects.
When using an object, the colon is used to show key-value pairs.
var object = {
innerFct: function(){
console.log('rawr');
},
someVariable: 7
}
object.innerFct(); //logs rawr
object.someVariable = 4; //just changed from 7 to 4
Using a colon how you have it in your example is incorrect syntax. Also when you are creating a function within an object like that, you don't name the function again because you are already assigning it to a name on the object.
Then you can edit the function anytime by doing something like this:
object.innerFct = function(){
//new code
}
Doing object.innerFct() will call the function.
Other answers have sufficiently covered the object syntax and calling the function in scope. As I mentioned in the comment, you can just do this:
function outer(){
(function () {
var c = "inner";
console.log(c)
})();
}
window.outer();
And it logs inner just fine.
Edit: Private/hidden variables like innerFct in the original code sample can be captured in closures as well.
outer = function() {
var innerFct = function () { console.log("inner"); }
// innerFct is captured in the closure of the following functions
// so it is defined within the scope of those functions, when they are called
// even though it isn't defined before or after they complete
window.wrapper = function() { innerFct(); }
return function() { innerFct(); }
}
outer();
// each of these next three lines logs "inner"
window.wrapper(); // assigned to global variable
outer()(); // calling the returned function
var innerFctBackFromTheDead = outer(); // saving the returned function
innerFctBackFromTheDead();
There is also the object constructor/prototype syntax.
function Outer() {
this.inner = function() {
this.c = "inner";
console.log(this.c);
}
}
var out = new Outer();
out.c; // undefined
out.inner(); // logs "inner"
out.c; // "inner"
More information on the new keyword and prototypes: http://pivotallabs.com/javascript-constructors-prototypes-and-the-new-keyword/
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.
What is the difference between declaring a variable with this or var ?
var foo = 'bar'
or
this.foo = 'bar'
When do you use this and when var?
edit: is there a simple question i can ask my self when deciding if i want to use var or this
If it is global code (the code is not part of any function), then you are creating a property on the global object with the two snippets, since this in global code points to the global object.
The difference in this case is that when the var statement is used, that property cannot be deleted, for example:
var foo = 'bar';
delete foo; // false
typeof foo; // "string"
this.bar = 'baz';
delete bar; // true
typeof bar; "undefined"
(Note: The above snippet will behave differently in the Firebug console, since it runs code with eval, and the code executed in the Eval Code execution context permits the deletion of identifiers created with var, try it here)
If the code is part of a function you should know that the this keyword has nothing to do with the function scope, is a reserved word that is set implicitly, depending how a function is called, for example:
1 - When a function is called as a method (the function is invoked as member of an object):
obj.method(); // 'this' inside method will refer to obj
2 - A normal function call:
myFunction(); // 'this' inside the function will refer to the Global object
// or
(function () {})();
3 - When the new operator is used:
var obj = new Constructor(); // 'this' will refer to a newly created object.
And you can even set the this value explicitly, using the call and apply methods, for example:
function test () {
alert(this);
}
test.call("hello!"); //alerts hello!
You should know also that JavaScript has function scope only, and variables declared with the var statement will be reachable only within the same function or any inner functions defined below.
Edit: Looking the code you posted to the #David's answer, let me comment:
var test1 = 'test'; // two globals, with the difference I talk
this.test2 = 'test'; // about in the beginning of this answer
//...
function test4(){
var test5 = 'test in function with var'; // <-- test5 is locally scoped!!!
this.test6 = 'test in function with this'; // global property, see below
}
test4(); // <--- test4 will be called with `this` pointing to the global object
// see #2 above, a call to an identifier that is not an property of an
// object causes it
alert(typeof test5); // "undefined" since it's a local variable of `test4`
alert(test6); // "test in function with this"
You can't access the test5 variable outside the function because is locally scoped, and it exists only withing the scope of that function.
Edit: In response to your comment
For declaring variables I encourage you to always use var, it's what is made for.
The concept of the this value, will get useful when you start working with constructor functions, objects and methods.
If you use var, the variable is scoped to the current function.
If you use this, then you are assigning a value to a property on whatever this is (which is either the object the method is being called on or (if the new keyword has been used) the object being created.
You use var when you want to define a simple local variable as you would in a typical function:-
function doAdd(a, b)
{
var c = a + b;
return c;
}
var result = doAdd(a, b);
alert(result);
However this has special meaning when call is used on a function.
function doAdd(a, b)
{
this.c = a + b;
}
var o = new Object();
doAdd.call(o, a, b);
alert(o.c);
You note the first parameter when using call on doAdd is the object created before. Inside that execution of doAdd this will refer to that object. Hence it creates a c property on the object.
Typically though a function is assigned to a property of an object like this:-
function doAdd(a, b)
{
this.c = a + b;
}
var o = new Object();
o.doAdd = doAdd;
Now the function can be execute using the . notation:-
o.doAdd(a, b);
alert(o.c);
Effectively o.doAdd(a, b) is o.doAdd.call(o, a, b)
var foo = 'bar'
This will scope the foo variable to the function wrapping it, or the global scope.
this.foo = 'bar'
This will scope the foo variable to the this object, it exactly like doing this:
window.foo = 'bar';
or
someObj.foo = 'bar';
The second part of your question seems to be what is the this object, and that is something that is determined by what context the function is running in. You can change what this is by using the apply method that all functions have. You can also make the default of the this variable an object other than the global object, by:
someObj.foo = function(){
// 'this' is 'someObj'
};
or
function someObj(x){
this.x=x;
}
someObj.prototype.getX = function(){
return this.x;
}
var myX = (new someObj(1)).getX(); // myX == 1
In a constructor, you can use var to simulate private members and this to simulate public members:
function Obj() {
this.pub = 'public';
var priv = 'private';
}
var o = new Obj();
o.pub; // 'public'
o.priv; // error
Example for this and var explained below:
function Car() {
this.speed = 0;
var speedUp = function() {
var speed = 10; // default
this.speed = this.speed + speed; // see how this and var are used
};
speedUp();
}
var foo = 'bar'; // 'var can be only used inside a function
and
this.foo = 'bar' // 'this' can be used globally inside an object
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);