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.
Related
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 am trying to get private properties to work in javascript.
var obj = function() {
var a = 0;
this.run = function() {
var q = a;
a += 1;
return q;
};
};
alert(obj.run());
alert(obj.run());
I have a private variable a and a public function run, however when I call it, it throws an error saying obj.run is not a function. Does anyone know what's wrong?
Thanks
You should create instance of your obj
var o = new obj();
console.log(o.run());
console.log(o.run());
Example,
or you can use module pattern, like so
var obj = (function() {
var a = 0;
return {
run: function () {
var q = a;
a += 1;
return q;
}
};
})();
console.log(obj.run());
console.log(obj.run());
Example
the value of this is determined by how a function is called. (Context)
your obj is a function type. It has not been called, not been invoked, or no instance of it has been created yet. Thats y 'this' here refers to window object, not function obj type. Context is 'window' here
this.run = function () {
//code
}
// here the context is window, hence attaches run property to window
// object making run method accessible in global scope.
When you do
obj.run()
// remember 'this' to be window , this statement will not work,
// because obj doesn't have run property.
When you create instance of obj like
var o = new obj(); // context of 'this' is set to function now
so, if you call o.run() // it will work.
this in javascript
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.
a = function (){
var b = 10;
var k = function(){
console.log(b);
}();
}();
The above code will print 10.
var k = function(){
console.log(b);
}
var a = function (){
var b = 10;
k();
}();
This code will print undefined.
Is it possible to print 10 instead? Like binding the scope to k before calling it.
As #Derek answered, you can obviously pass an argument.
Aside from that, you can't transfer or change variable scope, but you can directly manipulate calling context.
As such, you can set b as the property of an object, and set that object as the calling context of whatever function you're calling.
var k = function(){
console.log(this.b);
}
var a = function (){
var obj = {b:10};
k.call(obj);
}();
The .call() method invokes the k function, but sets the first argument you provide as the calling context of the called function.
In fact, you don't technically need to use an object. You could directly set the number as the value to use...
var k = function(){
console.log(this);
}
var a = function (){
var b = 10;
k.call(b);
}();
In strict mode, you'll get the number, but in non-strict, you'll get the Number as its object wrapper.
Really? What have you tried?
var k = function(b){
console.log(b);
}
var a = function (){
var b = 10;
k(b); //Done.
}();
Why does it give you undefined in your second example is because b is not defined. You have to define it first before using the variable b.
var k = function(b){ //<--There, defined. Mission accomplished.
Access into the scope can be granted through eval.
var a = (function() {
var b = 10;
return {
eval: function(s) {
return eval(s);
}
};
})();
var k = function() {
console.log(a.eval("b"));
};
k();
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);