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();
Related
This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 1 year ago.
I have a Javascript object that stores a bunch of methods, and also stores some variables. In the normal case when the methods are trying to access each other or the variable it works fine, but if the methods are called from out of scope (say, via another callback) they are no longer able to access the variable.
Example JSFiddle here: http://jsfiddle.net/3Lkuz2Lk/2/
Below is the sample code to illustrate the issue:
var obj = {
x: null,
func1: function() {
console.log('func1, x is ' + this.x);
},
func2: function() {
console.log("func2");
this.func1();
var func1 = this.func1;
func3(function() {
func1();
});
}
};
function func3(callback) {
console.log("func3");
return callback();
}
obj.func2();
The output from the above code is:
func2
func1, x is null
func3
func1, x is undefined
What's not clear to me is why the second time func1 is called x is undefined?
If I need to accomplish this (i.e., be able to access the methods and variables within the object no matter which context they're called from), how can I accomplish that? I find the above approach to be unclean since I need to store the func1 reference in order to be make it available to the call to func3, and I'm hoping there's a cleaner/simpler approach.
var obj = {
x: null,
func1: function() {
console.log('func1, x is ' + this);
},
func2: function() {
console.log("func2");
this.func1();
var func1 = this.func1;
func3(func1);
}
};
function func3(callback) {
console.log("func3");
return callback();
}
obj.func2();
This is because this is different in both cases, in the first case this points to the Object while in the next one this refers to the global object/ window. you would have to do
var obj = {
x: null,
func1: function() {
console.log('func1, x is ' + this.x);
},
func2: function() {
console.log("func2");
this.func1();
var func1 = this.func1.bind(this);
func3(func1);
}
};
function func3(callback) {
console.log("func3");
return callback();
}
obj.func2();
You have to use bind(this), read more about it here:
var func1 = this.func1.bind(this);
I've simplified the code. The problem is the reference. You call upon func3, which is in its own scope and not part of the scope chain of obj. So this refers to the scope of the func3. If you bind the this from obj to the callback it works.
var obj = {
x: null,
func1: function() {
console.log('func1, x is ' + this.x);
},
func2: function() {
console.log("func2");
this.func1();
func3(this.func1.bind(this));
}
};
function func3(callback) {
console.log("func3");
return callback();
}
obj.func2();
Another solution using call is in this fiddle http://jsfiddle.net/3Lkuz2Lk/3/
Is there a more elegant way of writing something like this, where myFunction is asigned to the function func but func is also executed during the assignment?
var myFunction = (function(){
var func = function(){
console.log('hello world');
};
func();
return func;
})();
...
myFunction();
var myFunction = (function func(){
console.log('hello world');
return func;
})();
You can name your anonymous function. This name will only be accessible inside of the function itself, though.
Your core statement is this
var <name> = (<functionExpression>)();
I don't see how this could be more elegant.
Assignments expressions return the assigned value, but you have to declare the variable separately so you still have to repeat the identifier:
var outer;
(outer = function() {
var inner;
return (inner = function() {
print('hello world');
})(), inner;
})();
outer();
That said if I saw this code from a coworker I'd whap him with a rolled up newspaper.
why doesn't this work as expected. (see expected comment)
var Module = function () {
var public_instance_var;
function doStuff () {
Module.doOtherStuff();
console.log(public_instance_var); // expected: true, but logs undefined
};
function doOtherStuff() {
public_instance_var = true;
};
return {
public_instance_var: instance_var,
doStuff: doStuff,
doOtherStuff: doOtherStuff
}
}();
Module.doStuff();
Update: Fixed accordingly to a few of jAndy suggestions
Multiple errors here:
You don't return DoStuff as module interface
instance_var is not declared, probably meant public_instance_var
doOtherStuff is never assigned to Module, just call it like doOtherStuff();
Fixed code:
var Module = function () {
var public_instance_var;
function doStuff() {
doOtherStuff();
console.log(public_instance_var); // expected: true, but logs undefined
};
function doOtherStuff() {
public_instance_var = true;
};
return {
doStuff: doStuff,
public_instance_var: public_instance_var
}
}();
Module.doStuff();
change your code like so
var Module = function () {
var public_instance_var;
function doStuff () {
doOtherStuff();
console.log("var is ", public_instance_var); // expected: true, but logs undefined
};
function doOtherStuff() {
public_instance_var = true;
};
return {
public_instance_var: public_instance_var,
doStuff : doStuff
}
}();
Module.doStuff();
you have to return doStuff() function (otherwise outside it will be undefined) and public_instance_var instead of instance_var
you need to execute doOtherStuff() without prefixing Module.
What this code does is, simply put: create and run a function and assign its return value to a variable: Module. The return value is an object with 1 property: public_instance_var, that points to the variable instance_var, or (after correcting the typo: public_instance_var). This variable was declared, but not instantiated. Therefore the return value looks like this:
Module.public_instance_var = undefined
The very last line Module.doStuff(); won't work one bit: Module is an object that has no methods. The functions you declared are garbage collected when the anonymous function returns. If you want access to those functions, you'll need to include them in the return statement. Read up on closures, Object constructors and design patterns in general, but I'd say the code you're after will look something like this:
var Module = (function()
var public_instance_var;
function doStuff () {
this.doOtherStuff();
console.log(public_instance_var); // expected: true, but logs undefined
};
function doOtherStuff() {
public_instance_var = true;
};
return {
public_instance_var: public_instance_var,
doStuff: doStuff,
doOtherStuff: doOtherStuff
};
})();
Of course, this way your variable public_instance_var is a public property, so my guess would be what you're really trying to do is simulate a private properties and methods. In which case you might end up with code similar to this:
var Module = (function()
{
var public_instance_var;
return {
//public_instance_var: public_instance_var, remove this line
//the closure will preserve access to the variable
doStuff: function ()
{
this.doOtherStuff();//this, you're referencing the object's property
console.log('here I am');
},
doOtherStuff: function ()
{
public_instance_var = true;
//this won't work anymore:
//this.public_instance_var = true;
};
}
})();
Module.doStuff() now logs here I am, but the doOtherStuff is now a public method, too. Here's how you might choose to solve the issue:
var Module = (function()
{
var public_instance_var;
function doOtherStuff ()
{
public_instance_var = true;
};
return {
//public_instance_var: public_instance_var, remove this line
//the closure will preserve access to the variable
doStuff: function ()
{
doOtherStuff();//don't use this here, but the reference to the function exists thanks to closure
console.log('here I am');
console.log(public_instance_var);//logs true
}
};
})();
These are just a few of the very powerful things you can do with closures and functions returning objects. Just read a couple of articles, like this one, there are better ones out there. Google the term power constructors
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() {
// ...
}
How to do this?
var obj = {
func1 : function(){
// Do stuff
},
func2 : function(){
func1(); // does not work
this.func1(); // does not work
}
}
Edit: missed a semicolon
var obj = {
func1 : function(){
// Do stuff
},
func2 : function(){
obj.func1(); // It works fine
}
}
if you want to use the 'this' keyword, you should do something like
function obj() {
this.param = whatever;
}
obj.prototype.method1 = function(){
...
}
obj.prototype.method2 = function(){
this.method1();
}
you could declare the methods in the obj function, but it is better to use prototype, because it is more efficient -- no matter how many obj instances you create, the functions only exist once. If you put the functions in the obj constructor, each instance of obj has its own copy of the function. javascript does some magic to associate the method call with the object instance on which it is called, to make sure 'this' means the right thing in context
I don't know why the person asking the original question thought that wouldn't work. Their example does work.
var obj = {
func1 : function(){
console.log("doing stuff");
},
func2 : function(){
this.func1(); // works fine!
}
}
You can paste that into the console and call obj.func2() and it works just fine. You don't need to name the object in this situation.
But be careful. This solution wouldn't work if you define another anonymous function inside of func2, and then try to use "this" inside of that function (such as if you're defining a callback). You'll get a "Uncaught TypeError: this.func1 is not a function" error. The problem in that situation is that "this" no longer refers to the outer object, it now refers to the context of that new inner function. For example:
var obj = {
func1 : function(){
console.log("doing stuff");
},
func2 : function(){
var func3 = function () {
this.func1(); // doesn't work ("this" is no longer obj)
}
func3();
}
}
To fix that issue, you could save a local copy of "this". Example:
var obj = {
func1 : function(){
console.log("doing stuff");
},
func2 : function(){
var ourThis = this;
var func3 = function () {
ourThis.func1(); // works fine!
}
func3();
}
}
Another way is to create your object through a factory function. That way, you can initialize your functions and use them inside the others.
const objFactory = () => {
const func1 = () => {
// Do stuff
}
const func2 = () => {
func1(); // This will work
}
return { func1, func2 }
}
const obj = objFactory();
obj.func1();
obj.func2();