See the following code:
function parent(child) {
var a = 4;
var b = 5;
child();
}
parent(function() {
console.log(a + b);
})
Here I understandably get:
Uncaught ReferenceError: a is not defined.
Is there anything I can do to change only the parent function so that the console.log() in the child function has access to a and b so that it can reference it in that way?
I know I can pass a and b into child as arguments, but I'm wondering if I can somehow call the child function with the parent scope injected into it so that I don't need to list the parameters in the child function.
I also looked at .call(), .apply(), and .bind(), but it seemed that would only help if I wrote this.a and this.b in both parent AND the child function.
You could use the window (by referencing this) to add globals to it, but this method isn't very nice, to say the least:
function parent(child) {
var a = 4;
var b = 5;
this.a = a;
this.b = b;
child();
}
parent(function() {
console.log(a + b);
})
Another ugly solution would be to use eval, which I do not reccomend either:
function parent(child) {
var a = 4;
var b = 5;
eval('var f = '+child);
f();
}
parent(function() {
console.log(a + b);
})
You're most likely better of passing through the variables like you mentioned above:
function parent(child) {
var a = 4;
var b = 5;
child(a, b);
}
parent(function(a, b) {
console.log(a + b);
})
Or, you could wrap your child function in a wrapper function (i.e. make it a closure), which can accept parameters a, b, for your child() to use like so:
function parent(child_wrapper) {
var a = 4;
var b = 5;
var child = child_wrapper(a, b);
child();
}
parent(function(a, b) { // wrapper function
return function() { // original child function (untouched, just being returned by the wrapper function)
console.log(a + b);
}
})
Related
I was given this snippet to debug in one of my interviews.
var module = (function sumModule(){
var a = 0;
var b = 0;
const init = (a,b) =>{
a = a;
b = b;
}
function sum() {
return a+b;
}
return {
sum: sum,
init
}
})();
module.init(1,2);
console.log(module.sum())
The value being returned is 0 (0+0), the assignment of a and b in func init didn't overwrite the global var a and var b. Why is this so, can someone please explain?
NOTE: I was told to fix it without renaming the function parameters (a,b).
Instead of renaming the parameters you can also refer to the global variables via their namespace like you do with the init function.
*Or just rename the global variables, if that is allowed
var module = (function sumModule(){
var a = 0;
var b = 0;
const init = (a, b) => {
module.a = a;
module.b = b;
}
function sum() {
return module.a + module.b;
}
return {
sum: sum,
init,
}
})();
module.init(1, 2);
console.log(module.sum())
Because a and b in the assignments of init() function refers to its parameters, not the outer a and b.
So those assignments don't affect values of the outer a and b.
Modified answer from #reyno.
His example just monkey patch a & b to the module object after the .init call. Therefore this variables are public and not private anymore.
With this you get the same result, but maintain the variables a & b private.
To achieve this, use a private namespace object, like i did with private.
var module = (function sumModule(){
var private = {
a: 0,
b: 0
}
const init = (a, b) => {
private.a = a;
private.b = b;
}
function sum() {
return private.a + private.b;
}
return {
sum: sum,
init,
}
})();
console.log(module) // no a or b property
module.init(1, 2);
console.log(module.sum())
console.log(module) // still no a or b property
I'm learning JS and am wondering, is there a way to return the function bar() or buz() by without returning foo()? For example, if I wanted to return the function bar(); to get 2, could I do that? Would it be something like foo().bar(); ?
// Nested Scopes
function foo() { // can only access itself
var a = 1;
function bar() { // access to foo(), not buz()
var b = 2;
function buz() { // access to bar() and foo()
var c = 3;
console.log(a, b, c); // 1, 2, 3
}
buz();
console.log(a, b); // 1, 2
}
bar();
console.log(a); // 1
}
foo(); // 1
Certainly. You can return an object at each stage which holds the function, or you can return the function itself. This utilizes what's called a closure.
function foo() {
var a = 1;
function bar() {
var b = 2;
function buz() {
var c = 3;
console.log(a, b, c);
}
console.log(a, b);
return { buz: buz };
}
console.log(a);
return { bar: bar };
}
foo().bar().buz();
You can do this, but it’s quite over-complicated.
The basic syntax is:
foo().bar().buz();
Where-ever you add another () after an existing one, it’ll print that level out. See the snippet for examples.
// Nested Scopes
function foo() { // can only access itself
var a = 1;
function bar() { // access to foo(), not buz()
var b = 2;
function buz() { // access to bar() and foo()
var c = 3;
return (function() {
console.log(a, b, c);
});
}
return (function() {
var tmp = function() {
console.log(a, b);
return {
buz: buz
};
};
tmp.buz = buz;
return tmp;
})();
}
return (function() {
var tmp = function() {
console.log(a);
return {
bar: bar
};
};
tmp.bar = bar;
return tmp;
})();
}
foo().bar().buz(); // (nothing)
foo().bar()().buz(); // 1, 2
foo()().bar()().buz(); // 1 // 1, 2
foo()().bar().buz()(); // 1 // 1, 2, 3
foo()().bar()().buz()(); // 1 // 1, 2 // 1, 2, 3
This kind of abuses the fact that you can assign properties to anything in JavaScript, including functions.
foo is a function that refers to the outer foo.
foo() is another function that refers to that inner tmp which has a bar property that refers to the inner bar function.
foo()() actually calls that inner tmp function but still leaves you with an object that has a bar property that again refers to the inner bar function.
This approach is basically the same for bar.
For buz, however, (something).buz() is just a function, without any extra properties and (something).buz()() doesn’t return anything, because that’s the final level.
you do this more like setting a variable.
var foo = {
bar: function() {
return 3;
}
}
console.log(foo.bar());
In many functions I have noticed the following pattern: function declares variables, combines it to the result and returns result. It is shown in this very simple example:
function fn() {
var a = 1,
b = 2;
return a + b;
}
fn(); // 3
or:
function fn() {
var a, b;
return a = 1,
b = 2,
a + b;
}
fn(); // 3
I would like to minimize this code and reduce it to the one statement. It could look like this:
function fn() {
return a = 1,
b = 2,
a + b;
}
However this code declares variables a, b in global scope which is not acceptable. Is it possible to do this in javascript?
Maybe this works for you, which is not advisable because of using assignment alogn with the comma operator.
function fn(a, b) { // declaration in local scope
return a = 1, b = 2, a + b; // return value with comma operator
}
A newer approach takes default values and returns just the addition of both.
fn = (a = 1, b = 2) => a + b;
What you are trying to do (declare using var and return in same statement) is not possible with JavaScript syntax.
The most concise you can get is your first option:
function fn() {
var a = 1,
b = 2;
return a + b;
}
fn(); // 3
My code looks like this:
function x(a,b)
{
return a + b;
}
var f = x;
function x(a,b)
{
return a - b;
}
var res = f(2,1);
I expect that the result is 3 as f is pointing to function x before modifying it, but it isn't the case, how can I keep a reference to a function that is foing to be redefined?
Function declarations are processed before expressions. Therefore, from the point of view of the interpreter, your code is interpreted as this:
function x(a,b)
{
return a + b;
}
function x(a,b)
{
return a - b;
}
var f = x;
var res = f(2,1);
The solution is to re-assign the function using a function expression instead of a function declaration. This is because as I mentioned above expressions are processed after declarations:
function x(a,b)
{
return a + b;
}
var f = x;
x = function (a,b) // <--------- this fixes your problem
{
return a - b;
}
var res = f(2,1);
Note, that since declarations are processed before expressions, the following would work as well:
var f = x;
x = function (a,b)
{
return a - b;
}
var res = f(2,1);
function x(a,b) // this is processed first
{
return a + b;
}
Functions and variable declarations (but not variable assignments) are "hoisted" to the top of their containing scope.
So your code is equivalent to this:
function x(a,b) {
return a + b;
}
function x(a,b) { //this overwrites the previous function declaration
return a - b;
}
var f;
var res;
f = x;
res = f(2,1); //1
It should now be clear why f(2,1) is 1 instead of 2.
You can overcome this by creating functions as variables instead:
var x = function(a, b) {
return a + b;
}
var f = x;
console.log(f(2, 1)); //3
var x = function(a, b) {
return a - b;
}
var f = x;
console.log(f(2, 1)); //1
Assign your functions to variables when creating them:
var f1 = function(a, b) {
return a + b;
}
var f2 = f1;
f1 = function(a, b) {
return a - b;
}
alert( f1(2,1) ); // < Will subtract
alert( f2(2,1) ); // < Will add
This allows you to easily clone the function.
I have the following scenario. I have an object 'a' with two callback methods however one callback requires access to the other callback variable value (for modifications / to read value / update value). I would like to know what is the best approach to structuring this code without placing the variable b into global scope. Under is the code and a jsfiddle.
Code
var a = {
load: function(){
var b = 25;
console.log(b);
},
add : function (b){
console.log('The value of b is '+ b);
}
};
Use a closure:
var module = (function () {
var b; //Scoped to this module
return { //Return object with methods
load: function () {
b = 25; //This refers to the module's b
console.log(b);
},
add: function () {
console.log('The value of b is '+ b);
}
};
})(); //Self invoking function, invokes instantly.
module.load(); //b is now 25.
module.add(); //The value of b is 25
console.log(b); //undefined, out of scope.
Now all the "private" variables are scoped directly to the module, and don't affect global scope.
// Alternative 1: Using a "private" variable
function A(b) {
// seal b in closure
var b = b;
this.load = function(){
b = 25;
console.log(b);
};
this.add = function(){
console.log('The value of b is '+ b);
};
this.getB = function(){
return b;
};
}
// Alternative 2: Using a object property
function A(b) {
// seal b in closure
this.b = b;
this.load = function(){
this.b = 25;
console.log(this.b);
};
this.add = .add = function(){
console.log('The value of b is '+ this.b);
};
}
var a = new A('foo');
var callback = a.load;
// ...