Say I have a given global IIFE closure
var foo = function(){
var x;
function doStuffToX(){
...
}
return { doStuff: doStuffToX }
}();
where x would be a reference to a DOM element.
Which of the below methods would be more efficient, given that there are 30+ of these DOM references, and foo.doStuff() would be rarely-sometimes invoked? Note that this would be a one-page app and therefore memory would not be cleared out.
Storing a reference to #x in foo.x
$(function(){
foo.init();
foo.doStuff();
});
var foo = function(){
var x;
function init(){
x = $('#x');
}
function doStuffToX(){
...
x.modifyDom();
...
}
return { init: init, doStuff: doStuffToX }
}();
Querying for #x in doStuff()s closure
$(function(){
foo.doStuff();
});
var foo = function(){
function doStuffToX(){
...
var x = $('#x');
x.modifyDom();
...
}
return { doStuff: doStuffToX }
}();
Related
I have an anonymous function inside a variable GLOBAL.
var GLOBAL = function (){
var func1 = function(){
console.log("function 1 go!")
}
var func2 = function(){
console.log("function 2 go!")
}
return {
init: function(){
func1();
}
}
}()
In my init function return func1, calling it so GLOBAL.init();.
My question is: how I can call functions directly for example GLOBAL.func1() or GLOBAL.func2().
You have to return the function references,
var GLOBAL = function (){
var func1 = function(){
console.log("function 1 go!");
}
var func2 = function(){
console.log("function 2 go!")
}
return { func1,func2 };
}();
Now you can access it like GLOBAL.func1() and GLOBAL.func2(). And do not confuse with the syntax { func1,func2 };. That is quite similar to { func1 : func1,func2 : func2 }; I just used the shorthand introduced in ES6.
You can't. They are locally scoped variables. Being inaccessible outside the function is a large part of the point.
If you want them to be accessible, then you need to make them so explicitly (as you have done for the anonymous function you assign to init).
You should explicit add those functions in the returned object. In this code you can still continue executing init() as a object initialization.
var GLOBAL = function (){
var func1 = function(){
console.log("function 1 go!")
};
var func2 = function(){
console.log("function 2 go!")
}
return {
init: function(){
this.func1();
},
func1,
func2
}
}();
GLOBAL.func1();
GLOBAL.func2();
I hope that helps :D
You can follow modular approach if it can help:
var GLOBAL = {
func1: function(){
console.log("function 1 go!")
},
func2: function(){
console.log("function 2 go!")
}
}
GLOBAL.func1();
GLOBAL.func2();
An example of this question is like this
var bar = (function(){
function foo(){
alert("foo");
}
function test(){
var f = "foo";
// I want to run f() to run the function foo
}
})();
If the function is in the global scope I can run it using window["foo"]() or if namespaced window["namespace"]["foo"]() but how can I run it inside like the example? I don't want to use eval().
A much clear example of what I want is like this:
var fns = ['a','b','c'],
bar = (function(){
function a(){
alert("a");
}
function b(){
alert("b");
}
function c(){
alert("c");
}
function test(array){
for(var i;i<array.length;i++){
//I want to run the functions that is on the array
// something like window[array[i]]() if function is in the global scope
}
}
return {
test : test
}
})();
bar.test(fns);
You can create a local object to reference the function, then access its property as you would with your window example.
var bar = (function(){
function foo(){
alert("foo");
}
var obj = {
foo: foo
};
function test(){
var f = obj["foo"];
f();
}
test();
})();
That's as close as you're going to get in a local scope without using eval.
You can create the object OR fn with this operator and make it an function with new constructor.
Creating an object.
https://jsfiddle.net/0Lyrz6rm/6/
var bar = {
foo: function(){
alert("foo");
},
test: function(){
var f = "foo";
return f;
}
}
bar["foo"]();
console.log(bar["test"]());
Another alternate way is to define the function as with constructor and little modification.
https://jsfiddle.net/0Lyrz6rm/4/
var bar = function(){
this.foo = function(){
alert("foo");
};
this.test = function(){
var f = "foo";
return f;
// I want to run f() to run the function foo
}
this.test2 = {
f: "foo"
}
}
var f = new bar();
f["foo"]();
console.log(f.test());
console.log(f.test2.f);
Here is a trivial use of a closure:
function Thing() {
var _x;
return {
setX: function(val) { _x = val; },
getX: function() { return _x }
};
}
var a = Thing();
var b = Thing();
a.setX(12);
b.setX(23);
a.getX(); //returns 12
What I want to do is be able to define the implementation of setX and getX outside the definition of Thing.
I tried something like this:
function setXimpl(val) {
_x = val;
}
function getXimpl() {
return _x;
}
function Thing() {
var _x;
return {
setX: setXimpl,
getX: getXimpl
};
}
var a = Thing();
var b = Thing();
a.setX(12);
b.setX(23);
a.getX(); //returns 23 not 12!
It's pretty obvious that setXimpl and getXimpl are setting/reading some globally scoped _x, rather than inside the closure.
I tried a bunch of other stuff (mostly syntactical changes), but I just can't get an outside function to be a part of the Thing closure. Is there any way to achieve what I want?
The very short answer to your question is no.
Closures work on the principle of accessing variables within function scope which are not accessible in global scope. This only occurs when the function doing the getting/setting are nested functions within a function that has returned (creating the closure). This implies new functions for setX and getX have to be created each time Thing is called, as in your Thing code.
This doesn't mean that functions returned from Thing can't call functions closer to global scope that are static by using (say) a IIFE
to define Thing:
var Thing = function(){
function a(...) {...}; // create once
function b(...) {...}; // create once
return function () { // the Thing function (create once)
var _x;
return {
setX: function(val) { _x = val; },
getX: function() { return _x }
};
};
}();
effectively giving the anonymous getter and setter functions access to statically defined encapsulated function helpers.
Try a factory:
function setXimplLoader(x) {
return function setXimpl(val) {
x.value = val;
};
}
function Thing() {
var _x = { value: '' };
return {
setX: setXimplLoader(_x),
getX: function() { return _x.value; }
};
}
var a = Thing();
var b = Thing();
a.setX(12);
b.setX(23);
console.log(a.getX())
Or use some utility library:
https://lodash.com/docs#partial
I have an object with two different sets of objects inside:
var myObj;
(function (myObj) {
var myFunction = (function () {
function myFunction(){
this.myValue = "something";
}
myFunction.getValue = function () {
var _this = this;
return _this.myValue;
}
return myFunction;
})();
myObj.myFunction = myFunction;
var myFunction2 = (function () {
function myFunction2() {
}
myFunction2.prototype.something = function () {
var a = myFunction.getValue();
}
return myFunction2;
})();
myObj.myFunction2 = myFunction2;
})(myObj || (myObj = {}));
Every time I run myFunction2.something(), a is assigned: undefined.
How can I get the value from myFunction into myFunction2.something()?
There is quite a mixup of scopes and design patterns in your code. Having 2 functions named the same way on inside the other creates different scopes for that name depending on where you call them. This quickly gets out of control. Like in this part:
var myFunction = (function () { // this guy is named myFunction
function myFunction(){ // this guy is also named myFunction
this.myValue = "something"; // 'this' here most certainly refers to 'window', not myFunction. Unless you do a 'new myFunction()' a la prototype
}
myFunction.getValue = function () {
var _this = this;// same here
return _this.myValue;
}
return myFunction;// here you are returning a function, not an object with methods
})();
Also I noticed that you are handling some logic with prototypes and other with closures, this also is kinda confusing when someone else (or you in a couple of months) need to refactor this code.
myFunction.getValue = function () {
var _this = this;
return _this.myValue;
}
return myFunction;
You could go all prototypes or all closures. I prefer closures so here is what I would do.
var myObj;
(function (myObj) {
// in this closure, we create a scope and return only the public methods
var myFunction = (function () {
// define properties here
var myValue = 'default value';
// define your methods, here we return
// myValue declared on the parent scope
function getValue() {
return myValue;
}
// this acts as a constructor, it autoexecutes
(function init(){
myValue = "something";
})();
// return all the functions in this scope
// you want to expose
return {
getValue: getValue
};
})();
// we then put myFunction into myObj
// at this point myFunction is an object with a method called getValue()
myObj.myFunction = myFunction;
var myFunction2 = (function () {
function something() {
// once this guy is called, we get the value from the other 'class'
var a = myFunction.getValue();
alert(a);// voila!
}
(function myFunction2() {
// do your init stuff here
})();
return {
something: something
};
})();
myObj.myFunction2 = myFunction2;
})(myObj || (myObj = {}));
// at this point myObj is an object with 2 'classes', each 'class' has its own methods
// we can proceed and call the desired method
myObj.myFunction2.something();
Demo: http://jsfiddle.net/bzw9kse7/
I've stepped through your code and just noticed a couple small things you're doing wrong.
You appear to be misdefining myFunction slightly, because it's not going to have myValue as a member variable, just a temporary variable that quickly falls out of scope. (And because it becomes undefined, it gets assigned to a, which is then unassigned).
So, replace these lines:
var myFunction = (function () {
function myFunction(){
var myValue = "something";
}
myFunction.getValue = function () {
var _this = this;
return _this.myValue;
}
return myFunction;
})();
With this:
var myFunction = (function () {
var myFunction = {};
myFunction.myValue = "something";
myFunction.getValue = function () {
var _this = this;
return _this.myValue;
}
return myFunction;
})();
EDIT Sorry, got this all wrong. It returns undefined because getValue is a static method of myFunction Object, not an instance method. That means that the this is not the same as in myFunction constructor.
Moreover you are not even attaching myValue to the this anywhere...
Edit 2 I added getMyValue to the myFunction prototype.
Try this:
....
var myFunction = (function () {
function myFunction(){
this.myValue = "something";
}
myFunction.prototype.getValue = function () {
return this.myValue;
}
// this creates the instance of the myFunction class.
return new myFunction();
})();
myObj.myFunction = myFunction;
...
// now you should be able to see the right result
var a = myFunction.getValue();
This is one of the craziest code I have ever seen, but the answer is this:
var a = myFunction.getValue(); is undefined because your 2nd definition of myFunction returns undefined, as in here:
function myFunction(){
var myValue = "something";
}
Your 2nd definition of myFunction actually replaces the 1st. See the comments below:
var myFunction = (function () {
// this definition replaces the one above
function myFunction(){
var myValue = "something";
}
myFunction.getValue = function () {
var _this = this;
return _this.myValue;
}
// which makes this return to not be taking in account when you are
// calling myFunction()
return myFunction;
})();
In the js code specified below -
var tclass = function(){
this.func2=function(){console.log('func2')};
this.b={
func1: function(){console.log('func1')}
}
}
how do i call func2 inside func1 on the same instance?
You'd have to keep a reference to both this and that function in the closure.
var tclass = function(){
var obj = this;
function func2(){console.log('func2')};
this.func2 = func2;
this.b={
func1: function(){ obj.func2(); }
}
}
Also it's more useful to declare functions with actual function declaration statements:
function tclass() {
// ...
}