Are following snippets exactly equal? If no what is the deference?
var x = (function() {
... //a
return function(){
... //b
};
})();
vs.
var x;
{
... //a
x = function(){
... //b
};
}
There is a major difference: In JavaScript, blocks don't induce a new variable scope. Therefore, you can't define private variables in the // a code block. Compare
var x = (function() {
var v = 42;
return function(){
return v;
};
})();
// v; would yield ReferenceError: v is not defined, so you need to call x
and
var x;
{
var v = 42;
x = function(){
return v;
};
}
// v is 42 here, that's not what's intended.
One major difference is that at the time of executing ...//a , x doesn't exist. Now in your case, in both cases it is undefined but generally speaking it's possible to access x variable during ...//a while in the first case it's not.
Otherwise in your circumstances it's pretty same. After all in your case the code is basically refactored into a separate function just like in any other language.
Related
var foo = (function(){
var x = "bar";
return function(){
console.log(x);
};
})();
console.log(foo.toString()); // function() {console.log(x);}
(foo)(); // 'bar'
eval('(' + foo.toString()+')()')); // error: x is undefined
Is there a technique for resolving (modifying) a function, so references from outer scope become local references, like:
function() {console.log(x);}
becomes:
function() {console.log("bar");}
The function can now be stringified and transported across a network and executed in another runtime.
Maybe one could parse the function to an Abstract Syntax Tree and then modify it? The reference will always be out of scope (not available), right?
The objective:
I am serializing a filter function from a node runtime to a postgresql plv8 runtime. Right now the filter function has interface: dbClient.filter((row, age) => row.age > age), ageFromOuterScope).then(matches => ...)
I want interface dbClient.filter((row) => row.age > age)).then(matches => ...), where age is a reference from outer scope.
Update:
I can only imagine one solution. Analyze the function, detect references to variables outside the function, and then rewrite the original function:
function(row) {
return row.age > age
}
To:
function(row, age) {
return row.age > age
}
Detected variables should also be added to a string that represent an array, like:
var arrayString = '[age]'
And then eval the string:
var functionArgs = eval(arrayString)
And finally:
dbClient.filter(modifiedFunction, ...functionArgs).then(matches => ...)
To expose the private variable outside the scope you need another function within the scope that rewrites the method description returned by toString. Then you use that function instead of toString to retrieve the method description.
var foo = (function(){
var x = "bar";
var f = function(){
console.log(x);
};
f.decl = function() {
return f.toString().replace("(x)", "(\""+x+"\")");
}
return f;
})();
console.log(foo.decl()); // function() {console.log("bar");}
eval("("+foo.decl()+")()"); // bar
I ran your top codebox's foo through Google's Closure Compiler, and it gave me this:
var foo=function(){return function(){console.log("bar")}}();foo;
not EXACTLY what you want, but you can get what you want from there using eval() and/or toString() as you're been tinkering with already.
I don't know how robust this is, and it makes other code mangles, but for the simple kind of functions you show, it does seem to consistently inline non-repeated primitives appearing in code.
You can bind the x to the function object itself.
var foo = (function(){
var x = "bar";
return function(){
this.x = x;
console.log(this.x);
};
})();
(foo)() // 'bar'
console.log(foo.toString()); // 'function() { this.x = x; console.log(this.x) }'
eval('(' + foo.toString()+')()'); // 'bar'
One more JavaScript scoping problem. I believe this is not related to 'hoisting'.
I've a small block of code here - http://jsfiddle.net/0oqLzsec/2/
var c = function(){
var x = 'before',
callBefore = function(){
alert(x);
},
callAfter = function(){
_callAfter();
};
return{
callBefore : callBefore,
callAfter : callAfter
}
var y = 'after';
function _callAfter(){
alert(y);
}
};
var obj = c();
obj.callBefore();
obj.callAfter();
callAfter() always alerts 'undefined' even if the variable y is defined before _callAfter(). But If I move the variable y declaration before variable x it is working.
I'm wondering if callAfter() can _callAfter() which is defined below, why can't it read variable y?
_callAfter and y are both hoisted, which makes them known as local variables through the function invocation. The _callAfter function is able to be called (as you do), and it also closes over the variable y. However, this variable does not get a value assigned before you return from the c function. Thus, you get undefined. It is the same if you put var y; BEFORE the return, and y='after'; after the return.
In other words, the following two are equivalent:
function foo(){
var a;
return function(){ return a };
a = 42; // never runs
}
alert( foo()() );
function bar(){
return function(){ return a };
var a = 42;
}
alert( bar()() );
Here's an example showing that the local variable is hoisted and closed over, even when the function literal occurs before the var in code:
function build() {
return function(newValue) {
alert("was: " + oldValue);
oldValue = newValue;
alert("now: " + oldValue);
}
var oldValue = 42;
}
f = build();
f(17);
// was: undefined
// now: 17
f(99);
// was: 17
// now: 99
It is related to hoisting, var y is moved to the top of the function, but the assignment (y = 'after') is not, so it never runs because it's after the return statement.
The JS engine rewrites your code to look something like:
var c = function(){
// functions also get hoisted to the top
function _callAfter(){
alert(y);
}
var x = 'before',
callBefore = function(){
alert(x);
},
callAfter = function(){
_callAfter();
},
// y declaration is hoisted to the top of the function
y;
return {
callBefore : callBefore,
callAfter : callAfter
};
// the assignment never gets called because it's after the return
y = 'after';
};
I have a self invoking function in javascript and I have another function in the same file where I need the value of a variable that is inside the self-invoking function. How can I do that?
Edit: So I can get one variable, but how about more variables or an array?
And I also have a semicolon at the beggining, how to deal with it:
;(function() {
...
})();
You need to set it as part of the return. Depending upon your exact pattern it could go like
var app =(function(){
var x = 5;
function app() {
}
app.x = x;
return app;
})();
Simple define the variable not in the function but before:
var a = 1;
(function(){ /* do stuff and use a*/})();
function(){
// use a again
}
var x = (function(y) { return y + 2; })(2);
alert(x);
Works just like this:
function addTwo(y) { return y + 2; }
x = addTwo(2);
//Your self invoking func
(function(){
var getStuff = holdsStuff();
console.log(getStuff.a); //getStuff.b, getStuff.cArr etc;
})();
//func in same file that holds the vars that you need.
function holdsStuff(){
var a = 10;
var b = 15;
var cArr = [1,2,3,4,5];
return { a: a, b: b, cArr: cArr};
}
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();
Why does this code:
function answer(x) {
function closure() {
var x = x || 42;
console.log(x);
}
closure();
}
foo();
always prints 42?
The logic would be that something like foo(31337) would print 31337, since in closure x would be 31337, so x || 42 would evaluate to 31337. But this is not the case.
I just can't figure this out, so I'm posting this here in hope of receiving enlightenment from one of the true javascript gurus out there.
function answer(x) {
function closure() {
var x = x || 42;
console.log(x);
}
closure();
}
answer(20);
inside closure your defining x as a local variable. This means it shadows the argument x from the answer function higher up the chain. Since you declared x with a var statement it defaults to undefined.
Then x || 42 is undefined || 42 which is 42.
The issue here is that your using the same name. If you did x = x || 42 it would be x = 28 || 42 which sets x to 28.
The distinction is using the var statement to create a new function local variable named x. Once you've done that, there is no way to reference variables of the same name that are higher up the scope chain.
To clarify how the interpreter works. Something like this :
function() {
var x = 52;
foo();
function foo() {
...
}
}
Gets converted into
function() {
function foo() {
}
var x;
x = 52;
foo();
}
var x in var x = x || 42; shadows the argument.
And since var ... is always parsed at the beginning of the function - i.e. before the assignment is executed, the outer x is never available in there.
Here's a better example:
(function(x) {
(function() {
alert(x);
var x = 'inside';
})();
})(123);
The execution order is basically:
Define var x with value undefined
Execute alert(x)
Assign 'inside' to x