javascript: access all variables of a parent function - javascript

I decided to create a funcB function that I call from funcA. I want all variables from funcA to be available in the funcB so func B can change that variables.
How to modify the code below so it meets my requirements? I doubt passing all variables it the only possible and the best way.
function funcB(){
alert(var1);//how to make it alert 5
alert(var20);//how to make it alert 50
}
function funcA(){
var var1=5;
...
var var20=50;
funcB();
}

var obj = {
one : "A",
two : "B",
fnA : function() {
this.fnB(); // without fnB method result will be displayed as A B, with fnB as C D
console.log(this.one + " " + this.two);
},
fnB : function() {
this.one = "C";
this.two = "D";
}
};
obj.fnA();
this keyword refers to obj object
You can define object with properties and methods inside it. With methods all the variables can be manipulated as you wish, from this example with fnB I'm changing values of properties which are displayed from fnA method
JSFiddle

One way is to drop the var keyword:
function funcB(){
alert(var1);//how to make it alert 5
alert(var20);//how to make it alert 50
}
function funcA(){
var1 = 5;
var20 = 50;
funcB();
}
This will expose them to the global scope so funcB can access them. Notice you can also create the varaibles in the global scope itself, with the var keyword, but both methods will ultimately have the same effect.
Note:
This may not work if there is already a var1 or var20 in the global scope. In such case, it will modify the global value and may result in unwanted errors.
This method is not preferred for official code, and is bad practice Reason

This is not possible as when you declare a variable with the var keyword, they are scoped to the function in which they are declared.
If you avoid the var keyword, they are instead defined as a global variable. This is deemed very bad practice.
I would recommend you read up on javascript coding patterns, particularly the module pattern.
For example:
var myNamespace = (function () {
var foo, bar;
return {
func1: function() {
foo = "baz";
console.log(foo);
},
func2: function (input) {
foo = input;
console.log(foo);
}
};
})();
Usage:
myNamespace.func1();
// "baz"
myNamespace.func2("hello");
// "hello"

Related

shorter way to collect many variables

function abc(){
var a = 'lorem';
var b = 'ipsum';
//... and so on - abot 20 variables.
// do something with the variables.
}
this variables I need in many functions so I tried to create a common function just for give them a value:
function givemevars(){
var a = 'lorem';
var b = 'ipsum';
...
}
and then
function abc(){
givemevers();
console.log(a);
}
result: undefined;
I know, I should firstly declare all that variables outside any function (like
var a; var b;...), but the question is - is there any shorter way?
update
I also tried:
function givemevars(){
a = 'lorem';
}
function abc(){
givemevers();
console.log(a);
}
result - undefined
function givemevars(){
a = 'lorem';
}
function abc(){
givemevars();
console.log(a);
}
abc();
You can re-structure you multiple variables to an object and wrap it to a method e.g giveMeVars() and just call it using object.key notation whenever you need any value from it.
function giveMeVars() {
const myVars = {
a: 'lorem',
b: 'ipsum',
c: 'zipsum'
//... and so on - abot 20 variables.
// do something with the variables.
}
return myVars;
}
function abc() {
let gotVars = giveMeVars();
console.log(gotVars.a);
}
abc();
Why your existing doesn't work?
Because it has typo on givemevars() and missing method invocation i.e abc(). Lets try like this way.
function givemevars() {
a = 'lorem';
}
function abc() {
givemevars();
console.log(a);
}
abc()
Okay, there are a couple things you need here.
First is an understanding of functional scope in javascript.
This will help you understand why your console.log is undefined;
Second, if you have 20 loose variables you might want to put them inside an object.
let variableContainer = {a:'ipsum', b:'lorum', c: 'whatever'};
variableContainer.d = 'something'; //add new variable or change existing
console.log(variableContainer.a); //access a
console.log(variableContainer); //view all
Now, you can just pass that object around to get its contents.
you are always going to have to declare all the variables, the question is where?
You can go with your first thought by declaring it outside a function, making a global object (or variable). From there you can call it anywhere in your script (including inside functions).
However, global variables are generally a bad practice. You had some of the right ideas before with you givemevars function. Try something like this:
function doWorkWithVariables(){
let variableObject = givemevars();
//now we do work with variables without having to make them global
console.log('vars', variableObject);
}
function givemevars(){
const myVariableObject = {
a: 'ipsum',
b:'lorem',
c:'something'
}
return myVariableObject;
}

How can I get the Function object in the body of such function?

Is there a way to get the Function object, while the function is executing?
I am assigning properties to my function, and want to access them. "this" doesn't help. Something like:
a.b=function(){...code...};
a.b.c=100;
I want to access a.b.c from the code in the function, without knowing its own name. "this" refers to a. How can get b?
I tried binding the function to his own object, but I couldn't.
Thank you.
I'm adding this example, I have to repeat after several different "theString" and "someSpecificValues":
Object.defineProperty(theObject, theString, {get: function(...){...}.bind(theObject, someSpecificValues), configurable: true});
You can use a named function expression for this:
var a = {};
a.b = function myFunc() {
console.log(myFunc.c);
};
a.b.c = 100;
a.b();
It allows code inside the function to access the function itself, but does not add the identifier to the enclosing scope.
Edit: Here is a more elaborate example of how the name myFunc only exists within the function:
var a = {};
a.b = function myFunc() {
console.log(myFunc.c);
};
a.b.c = 100;
a.d = function myFunc() {
console.log(myFunc.c);
};
a.d.c = 300;
a.b(); // logs 100
a.d(); // logs 300
console.log(typeof myFunc); // logs "undefined"
// create a myFunc variable
var myFunc = function() {
console.log("nooooooo!!!!");
};
a.b(); // STILL logs 100. the myFunc variable in this scope
// has no effect on the myFunc name that a.b uses
function callFunc(theFunc) {
theFunc();
}
callFunc(a.d); // STILL logs 300
// ===========================
function returnNamedFunction () {
return function myFunc() {
console.log(myFunc.c);
};
}
var iGotAFunction = returnNamedFunction();
iGotAFunction.c = 700;
iGotAFunction(); // logs 700
In the case when you cannot use a named function expression, e.g. when you are using .bind() on it, then an IIFE will suffice most of the time:
var myObj = {};
myObj.theFunc = (function () {
var f = function (arg1, arg2) {
console.log(this.theProp);
console.log(arg1);
console.log(arg2);
console.log(f.lista);
}.bind(myObj, "A!");
return f;
})();
myObj.theProp = "B!";
myObj.theFunc.lista = [1, 2, 3];
myObj.theFunc("C!");
There are two ways to get current function.
One is "almost deprecated" usage of arguments.callee. In function body it always refers to this function.
var a = {};
a.b = function () {
console.log(arguments.callee.c);
};
a.b.c = 100;
a.b();
arguments.callee is forbidden in strict mode. Reference.
The second one is using named function expression as JLRishe pointed.
arguments.callee pros and cons
Advantages:
it can be safely used with bound functions (arguments.callee refers to bound function)
it can be used with functions created using new Function
Disadvantages:
it can slow your program due to disabling certain optimisations
it's considered as almost deprecated
it can't be used in strict mode
Named function expression pros and cons
Advantages:
it's faster than arguments.callee
it's easier to understand how it works
Disadvantages:
it won't work as expected with bound functions (functionName will refer to original function, not bound one)
it can't be used in functions created with new Function

Access a function's property inside the function

I want to be able to assign a property to a function inside the function itself. I do not want to assign it to the object of invocation. So I want the equivalent of doing this:
var test = function() {
return true;
};
test.a = 'property on a function';
alert(test.a);
Instead of this, where the property is assigned to a global object:
var testAgain = function() {
this.a = "this property won't be assigned to the function";
return true;
};
testAgain();
alert(window.a);
Edit: To clarify, I'm wondering if there's something like this:
var test = function() {
function.a = 'property on a function';
};
alert(test.a); // returns 'property on a function'
Without knowing that the function is called test or having to execute it.
I know of course this isn't valid syntax
[is there a way to set a property on a function] without knowing that the function is called test or having to execute it.
Emphasis mine.
You can set a property on a function without knowing what its global variable name is necessarily going to be, however you do have to have a reference to the function in one way or another.
The module pattern is as close of a fit as I can think of:
window.test = (function () {
//the function could be named anything...
function testFn() {
...code here...
}
//...so long as the same name is used here
testFn.foo = 'bar';
return testFn;
}());
window.test.foo; //'bar'
The outer closure prevents testFn from being accessed anywhere globally, so all other references will have to use window.test.
This part of the answer is associated with the prior version of the question.
The simplest way of doing this is to use a named function:
var test = function testFn() {
testFn.foo = 'bar';
return true;
};
test.foo; //undefined
test();
test.foo; //'bar'
A better way of doing this is to use the module pattern so that you don't accidentally create issues with global leakage:
var test = (function () {
function ret() {
ret.foo = 'bar';
return true;
}
return ret;
}());
test.foo; //undefined
test();
test.foo; //'bar'
var testAgain = function() {
arguments.callee.a = "this property won't be assigned to the function";
return true;
};
testAgain();
alert(testAgain.a);​
You can do this by simple using the name to assign the property like this:
var test = function () {
test.a = 'a';
return true;
};
When test is invoked, the property will be set.
Demo
You could use arguments.callee, as su- said, but that's considered really bad practice. Also, it won't work in strict mode.
var test = function() {
test.a = 'a';
};
Or you can use prototypes, read more here.

How to cache/precalculate something(without global variable)?

What I want to do is to sending data between two handlers.
element.onmousedown = function() {
data = precalculate();
}
element.onmouseup = function() {
dosomething(data);
}
if the data is a global variable it works. People says global variable is evil. But I don't know how to do without it.
or I misunderstood "global variable"?
Just scope the variable if you don't want/need it to be global:
(function() {
var data;
element.onmousedown = function() {
data = precalculate();
}
element.onmouseup = function() {
dosomething(data);
}
})();
EDIT: To clarify, the only way to create a new variable scope in javascript is in a function.
Any variable declared with var inside a function is inaccessible to the outer scope.
In the code above, I created an IIFE (immediately invoked function expression), which is simply a function that is invoked as soon as it is created, and I placed your data variable (along with the handler assignments) inside of it.
Because the handlers were created in a scope that has access to the data variable, they retain their access to that variable.
To give another example:
var a = "a"; // global variable
(function() {
var b = "b"; // new variable in this scope
(function() {
var c = "c"; // new variable in this scope
// in this function, you have access to 'a', 'b' and 'c'
})();
// in this function you have access to 'a' and 'b' variables, but not 'c'
})();
// globally, you have access to the 'a' variable, but not 'b' or 'c'
In this case a global variable would make sense. Another possibility is to attach the value to the DOM element:
element.onmousedown = function() {
// 'this' should point to the element being mouse downed
this.data = precalculate();
};
element.onmouseup = function() {
// 'this' should point to the element being mouse upped
var data = this.data;
dosomething(data);
};
You misunderstood "global variable is evil".
In fact, what really happened is that someone wanted to be "part of the crowd", and so told you a sweeping generalisation, when in fact they should have said "only use global variables where appropriate".
Well, they are appropriate here, my friend.
JQuery makes this possible by using the .data() function:
http://api.jquery.com/jQuery.data/
You can get away with using global variables as long as you keep them to a minimum, for example you can place stuff in a single global namespace:
App = {};
element.onmousedown = function() {
App.data = "hello";
}
element.onmouseup = function() {
console.log(App.data);
}
Another more general solution is to create functions that cache their results using a technique that is called memoization. There's plenty of stuff if you search.
The following code does exactly that :
Function.prototype.memoize = function() {
var fn = this;
this.memory = {};
return function() {
var args = Array.prototype.slice.call(arguments);
return fn.memory[args] ? fn.memory[args] : fn.memory[args] = fn.apply(this, arguments);
};
};
e.g. You have an expensive function called exfunc..
newFunc = exfunc.memoize();
The above statement creates a new function called newFunc that caches the result of the original function so that the first time the actual code is being executed and all subsequent calls are retrieved from a local cache.
This mostly works with functions whose return value does not depend on global state.
More info :
http://osteele.com/archives/2006/04/javascript-memoization

Scope of self-invocation function in Javascript

Why does self-invocation function inside a function don't get the scope of the outer function in JavaScript?
var prop = "global";
var hash = {
prop: "hash prop",
foo: function(){
console.log(this.prop);
(function bar(){
console.log(this.prop);
})();
}
};
var literal = {
prop: "object"
};
hash.foo();
// hash prop
// global
hash.foo.call(literal);
// object
// global
Looks like altering the scope of the outer function has no effect on the scope of the inner self-invocation function.
PS: The question is not about how to alter the scope of the inner function. But what is the proper explanation in the "Javascript language" perspective? Does all self executing functions have 'global' scope by default? If so, why?
Your problem is the this and what it references:
foo: function(){
console.log(this.prop);
(function bar(){
console.log(this.prop); <--- this does not reference to foo here, but instead it refers to the window object
})();
}
You need to keep a reference to the outer this:
foo: function(){
console.log(this.prop);
var that = this;
(function bar(){
console.log(that.prop); <--- tada!
})();
}
Update
Some explanation. It's all about how JavaScript determines the context when invoking a function.
function Test() {
this.name = "Test";
this.bar = function() { console.log("My name is: "+ this.name);}
}
function Blub() {
this.name = "Blub";
this.foo = function() { console.log("My name is: " + this.name);}
}
var a = new Test();
var b = new Blub();
// this works as expected
a.bar(); // My name is: Test
b.foo(); // My name is: Blub
// let's do something fun
a.foo = b.foo; // make an educated guess what that does...
a.foo() // My name is: Test
Huh? Aren't we referencing the method of Blub? No we're not. We are referencing the unbound function of Blub.
JavaScript binds on . (dots) and based on that it decides waht the value of this should be.
Since you're not calling your anonymous function on an object (therefore no .) it will make this reference to the global object, which is - in case of the browser - the window object.
Another example (one might think this would work):
var str = "Hello World";
var ord = str.charCodeAt; // let's make a little shortcut here.... bad idea
ord(0) // no dot...
Instead of the char codes that are in str we get the ones that are in the global object, of course that's not a string so charCodeAt calls toString on which results in "[object DOMWindow]"
You are not applying any object as the this context when you call the inner function, so it gets this set to window by default. If you wanted to call the closure with the same this as the outer function, you would have to do:
(function bar(){
console.log(this.prop);
}).call(this);
Or:
var that = this;
(function bar(){
console.log(that.prop);
})();

Categories