I have following module
module.js
var Instance = (function () {
jsfunc('fn');
var fn = function () {
console.log('this in fn');
}
}());
jsfunc.js
function jsfunc(fn) {
// how to find if fn is defined in Instance module
}
As I am passing string, which is a function inside instance module. And then I want to check if that jsfunc's parameter function is defined inside Instance. How can I achieve this?
You need pass a function reference instead of a function name, since it is in a closure scope
var Instance = (function () {
var fn = function () {
console.log('this in fn');
}
jsfunc(fn);
}());
function jsfunc(fn) {
// how to find if fn is defined in Instance module
if (typeof fn == 'function') {
fn()
}
}
Demo: Fiddle
Also note that the value of Instance will be undefined since there is no value returned from the anonymous function.
Related
I had (approximately) this situation: I was trying to declare func1() function and add couple of static methods to it in one go by running it through _init() function providing a hash with properties to attach to it, not being aware of that it didn't remain declared in current scope after _init() function did it's job. It just got temporarily defined, and gc-ed after _init() run (as far as I'm aware). Here's the code sample:
//
// #_init
// merge src{} into target{}, overwriting
//
var _init = (function (target, src) {
var _ = this;
if (_.isobj(target))
_.keys(src).forEach(_.pass, {
src : src,
target : target
});
return target;
}).bind({
isobj : (function (node) {
return node === this(node);
}).bind(Object),
keys : (function (node) {
return this.keys(this(node));
}).bind(Object),
pass : function (field) {
this.target[field] = this.src[field];
}
});
, and I was hoping to 'batch-init' it here adding static methods at the same time:
_init(function func1 (e) {
var _api = func1.pop(arguments);
var node = this;
// and stuff...
}, {
pop: Function.prototype.call.bind(Array.prototype.pop),
// ...etc
});
When trying to reference it later I got error:
x = func1();
// ReferenceError: func1 is not defined
// x = func1()
Assigning the output of _init() to var func2 does the job, I can reference and use the function. Thing that confuses me is when console.log()-ing the func2 logs 'func1()', but trying to refernce func1 directly throws ReferenceError:
//
// #func2
//
var func2 = _init(function func1 () {
return func1.pop(arguments);
}, {
pop: Function.prototype.call.bind(Array.prototype.pop)
});
console.log(typeof func2, func2, func2(1,2,3));
// function func1() 3
console.log(func1(1,2,3));
// ReferenceError: func1 is not defined
// console.log(func1(1,2,3));
//
Could someone explain to me why the func1 reference didn't get created, but (strangely) was availble to func2 (it obviously was able to use it...)?
Could someone explain to me why the func1 reference didn't get created, but (strangely) was availble to func2 (it obviously was able to use it...)?
That's just how named function expressions work. Their name (func1) is available inside the function body as an identifier, but not outside. What happens to the result of the expression (passing the created function to _init, then assigning it to func2) is a different and completely unrelated thing.
I was trying to declare func1() function and add couple of static methods to it
You shouldn't, unless those static methods are really supposed to be public and not just simple helper methods. Use the revealing XY pattern (IEFE) and just get your utility functions in the closure scope:
var _init = (function() {
function isobj(node) {
return node === Object(node);
}
function pass(field) {
this.target[field] = this.src[field];
}
var keys = Object.keys;
return function (target, src) {
if (isobj(target))
keys(src).forEach(_.pass, {
src : src,
target : target
});
return target;
};
});
var func2 = (function() {
var pop = Function.prototype.call.bind(Array.prototype.pop);
return function func1 () {
return pop(arguments);
};
});
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
I'd like to call functions I've defined within the document ready function of jQuery, but am having a bit of trouble. I have the following code:
jQuery(document).ready( function($) {
function test1() {
alert('test1');
}
function test2() {
alert('test2');
}
var test_call = '2';
var fn = 'test' + test_call;
// use fn to call test2
});
I don't want to use eval, and window[fn] doesn't seem to be working. The two test functions don't appear to be indices in the window variable. I appreciate the help and knowledge.
All I can think of that doesn't use eval() or some form of eval (passing a string to setTimeout() is a form of eval()), is to register the relevant function names on an object and then look up the function name on that object:
jQuery(document).ready( function($) {
function test1() {
alert('test1');
}
function test2() {
alert('test2');
}
// register functions on an object
var funcList = {};
funcList["test1"] = test1;
funcList["test2"] = test2;
var test_call = '2';
var fn = 'test' + test_call;
if (fn in funcList) {
funcList[fn]();
}
});
or the registration could be done in the definition of the functions. If they were global functions, they would be implicitly registered on the window object, but these are not global as they are scoped inside the document.ready handler function:
jQuery(document).ready( function($) {
var funcList = {};
funcList.test1 = function test1() {
alert('test1');
}
funcList.test2 = function test2() {
alert('test2');
}
var test_call = '2';
var fn = 'test' + test_call;
if (fn in funcList) {
funcList[fn]();
}
});
Or, you could move the functions to the global scope so they are automatically registered with the window object like this:
function test1() {
alert('test1');
}
function test2() {
alert('test2');
}
jQuery(document).ready( function($) {
var test_call = '2';
var fn = 'test' + test_call;
if (fn in window) {
window[fn]();
}
});
The best way, if not Eval, would be to use setTimeout with zero milliseconds, as you can specify the function as a string.
setTimeout('myfunction()',0,);
When does it make sense to use function expressions instead of function declarations when implementing "private methods"? In both cases, the functions are encapsulated, the only practical difference appears to be that I wouldn't be able to call myFunc1 in the constructor. I know I should be using the prototype property either way, but I'm just curious.
function myClass
{
myFunc1() //error
myFunc2() //success
var myFunc1 = function()
{
}
function myFunc2()
{
}
}
You can call the function assigned to a variable, but you have to assign it before you can call it:
function myClass() {
var myFunc1 = function() {
}
myFunc1() //success
myFunc2() //success
function myFunc2() {
}
}
Those functions are local to the constructor, so it's not the same as using the prototype. To make a public function you need to assign it to the object:
function myClass() {
this.myPublicFunc1 = function() {
}
this.myPublicFunc2 = myFunc2;
function myFunc2() {
}
}
var o = new myClass();
o.myPublicFunc1() //success
o.myPublicFunc2() //success
You must use an expression if you want to invoke the function immediately.
This one invokes it and assigns the return value to the variable:
function myClass {
var myVar = function() {
return 'some value'; // <--- 2. assign the return value to the variable
}(); // <--- 1. invoke the function immediately
function myFunc2() {
}
}
This one invokes it, but assigns the function itself to the variable:
function myClass {
var myFunc1;
(myFunc1 = function() { // <--- 1. assign the function to the variable
// Do something
})(); // <--- 2. invoke the function immediately
function myFunc2() {
}
}
I know how to access the below member function when it's written like this:
var blady_blah=
{
some_member_function: function ()
{
}
}
I access it from outside doing blady_blah.some_member_function()
But how do I access the member function when it's written like this:
(function() {
some_member_function: function ()
{
}
})();
Braces, { }, are used to define both object literals and function bodies. The difference is:
var name = {}; // Object literal
Which you may also see written as
var name = {
};
That's just the same but with some space in between so it's still an object literal, and unfortunately it looks very similar to:
var name = function () { // Function body
};
An object can have members:
var name = {
member: "string"
};
Whereas a function cannot; a function has statements:
var name = function () {
do_something();
var result = do_something_else();
};
You can't write
var name = function () {
member: "string"
};
Because you've mixed the two uses of { } together.
A variable can be defined within a function, but it can't be seen outside the function - it's within the function scope:
var name = function () {
var something_useful = string;
};
The second example is a closure (it just happens to have a syntax error inside). Minus the bad syntax, your self-evaluating anonymous function looks like this:
(function() {
})();
If you'd like, you can define functions inside this that will be invisible to the outside world. This is useful if you're interested in maintaining a clean global namespace, for example with library code.
(function() {
function utilityFunctionFoo() {
}
function utilityFunctionBar() {
}
})();
Of course, if you'd like to call any of these functions from the outside world, you're out of luck. Or are you? Actually, there's another way to define a function:
var foo = function() {
}
That's exactly the same as writing:
function foo() {
}
...Except that when written in the second style, you can actually omit the var keyword and create a global variable! Bringing it all together:
(function() {
publicData = "stuff accessible from outside anonymous function";
var privateData = "stuff that stays inside anonymous function";
function utilityFunctionFoo() {
}
function utilityFunctionBar() {
}
usefulFunctionExport = function() {
utilityFunctionFoo();
utilityFunctionBar();
}
})();
usefulFunctionExport();
You can't access it after the function it's in terminates. It's a local variable that goes out of scope when its parent function ends.
You should make the main function be a constructor so that it returns a new instance of a class (you could name it Blahdy_blah) with the member function as one of its properties.
Look up constructors, their return values, and accessing member variables.
If you want to execute the function you need to return an object that exposes the function.
var LIB = (function() {
var fn = {
member_function : function(){}
};
return fn;
})();
and to call
LIB.member_function();
(function() {
blady_blah.some_member_function();
})();
If you need to add stuff into it you would write it like this.
(function() {
blady_blah.some_member_function(function(){
// Do stuff...
});
})();