IFFE vs. function that returns a function - javascript

Consider the following:
var x = (function(){
var _private = 'start';
var _x = function(text){
if(text){
_private = text;
}
else{
return _private;
}
}
return _x;
})();
console.log(x()); //start
x('end');
console.log(x()); //end
var y = function(){
var _private = 'start';
var _y = function(text){
if(text){
_private = text;
}
else{
return _private;
}
}
return _y;
}
console.log(y()); //toString of function
y();//invoked function, should return _y?
y('end')
console.log(y()); //toString of function
I need some clarity as to why the y function does not behave the same as the x function after it has been invoked. Why does the y function behave differently, and what overarching concept about IFFEs am I not getting?
fiddle: http://jsfiddle.net/xmmddcgn/

In the first example:
var x = (function(){
var _private = 'start';
var _x = function(text){
if(text){
_private = text;
}
else{
return _private;
}
}
return _x;
})();
var x is the inner function since the outer function was invoked.
In the second example var y is the outer function after you invoke it like this:
var y = function () {
var _private = 'start';
var _y = function (text) {
if (text) {
_private = text;
} else {
return _private;
}
}
return _y;
}
y(); // nothing happens and nobody keep _y's ref.
var p = y(); //p is _y
console.log(p()); //start
p('end')
console.log(p()); //end
Then p will be exactly the var x above.

Related

Function Call Hierarchy in JavaScript

My case it this:
function s () {
this.funcs = [];
this.funcs.addF = function (str) {
/* this will push a function to the funcs array, which uses getCoordX() and getPixelY() */
this.push (Function("pixelX", "var x = getCoordX(pixelX); var f = " + str + "; return getPixelY(f);"));
}
function getCoordX(a){
return 0;
}
function getPixelY(a){
return 0;
}
}
As you can see, in that array I'm adding functions that are created from strings, and those functions need do use getCoordX() and getPixelY(), which are in the s() object. When I try to access them it gives this error: Uncaught ReferenceError: getCoordX is not defined.
What should I do to make it work? Please help.
Edit 2
How i would use this code:
function s () {
this.funcs = [];
this.funcs.addF = function (str) {
/* this will push a function to the funcs array, which uses getCoordX() and getPixelY() */
this.push (Function("pixelX", "var x = getCoordX(pixelX); var f = " + str + "; return getPixelY(f);"));
}
this.drawCanvas = function() {
//some code goes here
this.drawGraph(c);
}
this.drawGraph = function (c) {
c.lineWidth = 2;
var cnt = 0; //count how many pixels have been rendered
for(var i = this.limitLeft; i < this.limitRight; i+= this.pixelwidth) {
for(var u = 0; u < this.funcs.length; u++) {
var f = this.funcs[u];
//some if statements go here
}
}
}
function getCoordX(a){
return 0;
}
function getPixelY(a){
return 0;
}
}
var canvas = document.createElement("canvas");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
canvas.id = "canvas";
document.body.appendChild(canvas);
var c = new Canvas("canvas");
c.funcs.addF("2*x");
c.drawCanvas();
You might do this:
function s () {
this.funcs = [];
this.funcs.addF = function (str) {
/* this will push a function to the funcs array, which uses getCoordX() and getPixelY() */
this.push (Function("pixelX", "getCoordX", "getPixelY", "var x = getCoordX(pixelX); var f = " + str + "; return getPixelY(f);"));
}
this.drawCanvas = function() {
//some code goes here
this.drawGraph(c);
}
this.drawGraph = function (c) {
c.lineWidth = 2;
var cnt = 0; //count how many pixels have been rendered
for(var i = this.limitLeft; i < this.limitRight; i+= this.pixelwidth) {
for(var u = 0; u < this.funcs.length; u++) {
var f = this.funcs[u];
var currvalue = f(i, getCoordX, getPixelY);
var lastvalue = f(i-1, getCoordX, getPixelY);
//some if statements go here
}
}
}
function getCoordX(a){
return 0;
}
function getPixelY(a){
return 0;
}
}
var canvas = document.createElement("canvas");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
canvas.id = "canvas";
document.body.appendChild(canvas);
var c = new Canvas("canvas");
c.funcs.addF("2*x");
c.drawCanvas();
This will do it. Hope this helps ;)
this isn't implicit in JavaScript, you must precise it.
Also don't use a string to create a function, just use
this.funcs.addF = function (str) {
var obj = this;
/* this will push a function to the funcs array, which uses getCoordX() and getPixelY() */
this.push (function(pixelX){
var x = obj.getCoordX(pixelX);
return obj.getPixelY(str);
});
}
The problem is that the Function constructor creates functions which run in the global scope. So your function can't access your getCoordX in the closure.
You could make getCoordX and getPixelY global functions:
function getCoordX(a) {
return a;
}
function getPixelY(a) {
return a;
}
function s() {
this.funcs = [];
this.funcs.addF = function (str) {
this.push(new Function("pixelX",
"var x = getCoordX(pixelX);" +
"var f = " + str + ";" +
"return getPixelY(f);"
));
};
}
var obj = new s();
obj.funcs.addF('x*3 + 5');
console.log(obj.funcs[0](1)); // 8
Alternatively, you could use the Function constructor only to evaluate str, and move the other code outside.
function s() {
this.funcs = [];
this.funcs.addF = function (str) {
var f = new Function('x', 'return ' + str);
this.push(function(pixelX) {
var x = getCoordX(pixelX);
return getPixelY(f(x));
});
};
function getCoordX(a) {
return a;
}
function getPixelY(a) {
return a;
}
}
var obj = new s();
obj.funcs.addF('x*3 + 5');
console.log(obj.funcs[0](1)); // 8
Here you have a full example with canvas:
function s() {
this.funcs = [];
this.funcs.addF = function (str) {
var f = new Function('x', 'return ' + str);
this.push(function(pixelX) {
var x = getCoordX(pixelX);
return getPixelY(f(x));
});
};
this.drawGraph = function(c) {
c.lineWidth = 2;
for(var u = 0; u < this.funcs.length; u++) {
var f = this.funcs[u];
c.beginPath();
c.moveTo(0, 200-f(0));
for(var x=1; x<400; ++x) c.lineTo(x, 200-f(x));
c.stroke();
}
};
function getCoordX(a) {
return a;
}
function getPixelY(a) {
return a;
}
}
var canvas = document.createElement("canvas");
canvas.width = 400;
canvas.height = 200;
document.body.appendChild(canvas);
var c = new s("canvas");
c.funcs.addF(".5*x");
c.funcs.addF("x + 50");
c.funcs.addF("3*x + 100");
c.drawGraph(canvas.getContext('2d'));

Accessing outer scope from inner scope

I have a type that looks a little something like this:
var x = function(){
this.y = function(){
}
this.z = function(){
...
this.A = function(){
CALLING POINT
}
}
}
From calling point, I'm attempting to call function this.y. I don't need to pass any parameters, but when I set some stuff from this.A, I need to call this.y.
Is this possible? I'm OK with passing extra parameters to functions to make it possible.
Is this possible?
Yes, you can assign this reference to another variable and then call function y on it
this.z = function() {
var self = this;
this.A = function() {
self.y();
}
}
Version with bind, basically this adds a new method a to the object.
var X = function () {
this.y = function () {
document.write('y<br>');
}
this.z = function () {
document.write('z<br>');
this.a = function () {
document.write('a<br>');
this.y();
}
}.bind(this);
};
var x = new X;
//x.a(); // does not exist
x.z(); // z
x.a(); // a y
Working example with saved inner this.
var X = function () {
var that = this; // <--
this.y = function () {
document.write('y<br>');
}
this.Z = function () {
document.write('Z<br>');
this.a = function () {
document.write('a<br>');
that.y();
}
}
}
var x = new X,
z = new x.Z; // Z
z.a(); // a y
Instead of function() you can try modern JavaScript or Typescript ()=>. I also like .bind(this).
You cannot because this.y() is not within the scope that this.A() is in. You can if you set this.y() to a global function y:
var y = function() {};
var x = function() {
this.y = y;
this.z = function() {
...
this.A = function() {
this.y(); // will be successful in executing because this.y is set to the y function.
};
}
};

Try to create object of returned function?

I was trying something different and ended up with these codes..
var f1 = function() {
this.x = 10;
this.innerf = function() { console.log(this.x); }
}
var of1 = new f1();
of1.innerf();
var f2 = function() {
return function() {
this.x = 10;
this.innerf = function() { console.log(this.x); }
}
}
var of2 = new f2();
of2.innerf();
It is throwing error ??! of2.inner is not a function
So, my anonymous function is returning same function body to my variable.
Why still i cannot able to instantiate??
The first part returns an object of which you can call the innerf method.
The second part returns a function that would return an object if you called it. But you don't.
This would work. Call the function f2(). It's return value is the anonymous function. Then, with new <return value of f2>(), you can create an instance of the object.
var f2 = function() {
return function() {
this.x = 10;
this.innerf = function() { console.log(this.x); }
}
}
var of2 = new (f2())();
of2.innerf();
// The two lines above can also be written as:
var of3constructor = f2(); // This returns the inner anonymous function.
var of3 = new of3constructor(); // This creates an instance by invoking the anonymous function.
of3.innerf();
Examples that work:
Creating it directly:
var f1 = function() {
this.x = 11;
this.innerf = function() {
console.log(this.x);
}
}
var of1 = new f1();
of1.innerf();
Returning a new object from a function:
var f2 = function() {
return new function() {
this.x = 12;
this.innerf = function() {
console.log(this.x);
}
}
}
var of2 = f2();
of2.innerf();
Returning an object:
var f3 = function() {
return {
x: 13,
innerf : function() {
console.log(this.x);
}
}
}
var of3 = f3();
of3.innerf();
Another one:
var f4 = function() {
return function() {
this.x = 10;
this.innerf = function() {
console.log(this.x);
}
}
}
var of4 = new (f2())();
of2.innerf();
Remember that when you call a function without the "new" keyword "this" points object where the functions was declared, in this case "window"
You need to return this from the inner function to the outer function. Also you need to run the inner function immediately.
jsFiddle:
http://jsfiddle.net/5dxybbb5/
var f1 = function() {
this.x = 10;
this.innerf = function() {console.log(this.x);}
}
var of1 = new f1();
of1.innerf();
var f2 = function() {
return function() {
this.x = 10;
this.innerf = function() {console.log(this.x);}
return this;
}();
}
var of2 = new f2();
of2.innerf();
Also this explains the () after a function declaration
What is the (function() { } )() construct in JavaScript?

Getting value of a CSS element

Can anyone tell me what the problem with this snippet of JS is? I am trying to assign the value of 'container's margin-top to the m variable.
function test()
{
var e = document.getElementById('container');
var m = e.style.getPropertyValue("marginTop");
alert (m);
}
edit: the alert was meant to display the value of m
You can try using this simple function:
function test()
{
var e = document.getElementById('container');
var m = getStyle(e, "marginTop");
alert ('hi ' + m);
}
function getStyle(el,styleProp)
{
if (el.currentStyle)
var y = el.currentStyle[styleProp];
else if (window.getComputedStyle)
var y = document.defaultView.getComputedStyle(el,null).getPropertyValue(styleProp);
else
var y = el.style[styleProp];
return y;
}
Try this:
function getStyle(elment, style) {
var x = document.getElementById(element);
if (x.currentStyle) {
var y = x.currentStyle[style];
} else if (window.getComputedStyle) {
var y = document.defaultView.getComputedStyle(x, null).getPropertyValue(style);
}
return y;
}
function test() {
var m = getStyle('container', 'margin-top');
alert(m);
}
Also, be careful with your variable scope. m won't be defined outside of test().

Anonymous self-invoking JavaScript function - returning multiple objects

If I have original function (as an example):
var x = function() { alert('tadaaa'); return 1; }
var y = function() { alert('tadaaa'); return 1; }
and I've gone ahead and made this into a self-invoking anonymous JS function, as such:
(function() {
var x = function() { alert('tadaaa'); return 1; }
var y = function() { alert('tadaaa'); return 1; }
})()
am I doing something paradoxical? I'd like to access x and y as global variables, but the self-invoking anonymous function is useful in other areas that I'm not going into detail right now - I just want to keep it.
Should I be doing something like:
var x= (function() {
var x = function() { alert('tadaaa'); return 1; }
var y = function() { alert('tadaaa'); return 1; }
// Should I be doing something like
return x
})()
or
var x= (function() {
var x = function() { alert('tadaaa'); return 1; }
return x
})()
var y = (function() {
var x = function() { alert('tadaaa'); return 1; }
return y
})()
seems somewhat redundant?
I'm not sure what the goal of al this is, but maybe you could return both functions in an object, like so:
var funcs = (function() {
var x = function() { alert('tadaaa'); return 1; };
var y = function() { alert('tadaaa'); return 1; };
return {x: x, y: y};
})();
funcs.x();
funcs.y();
This is basically what the Module Pattern is about (see for example http://www.adequatelygood.com/2010/3/JavaScript-Module-Pattern-In-Depth).
It's good! Depending on what you need, of course.
You can:
var x, y;
(function() {
x = function() { alert('tadaaa'); return 1; }
y = function() { alert('tadaaa'); return 1; }
})();

Categories