I have seen javascript something like this
var Gallery = function () {
var helloworld1 = function () {
alert('hey1');
}
var helloworld2 = function () {
alert('hey2');
}
var helloworld3 = function () {
alert('hey3');
}
}();
How would I call the helloworlds within this javascript file?
I've tried
helloworld1();
Gallery.helloworld1();
Gallery().helloworld1();
But they don't seem to work.
Also, are there any reasons why I should be writing my javascript in the above manner, rather than just using
function helloworld() {
alert('hey1');
}
Perhaps you want
var Gallery = {
helloworld1: function () {
alert('hey1');
},
helloworld2: function () {
alert('hey2');
},
helloworld3: function () {
alert('hey3');
}
};
Gallery.helloworld2();
or
var Gallery = function () {
this.helloworld1 = function () {
alert('hey1');
}
this.helloworld2 = function () {
alert('hey2');
}
this.helloworld3 = function () {
alert('hey3');
}
};
new Gallery().helloworld2();
Also, are there any reasons why I should be writing my javascript in the above manner?
It namespaces the functions. Everything to do with galleries is in the Gallery object.
Symbols declared in a function are only visible within that function (and inside other functions defined within it. That goes for symbols declared with var and function equally. Thus, in your first example, you cannot access those functions from outside the outer function.
Functions can be "exported" by having the outer container function return an object, with the functions as property values.
As to whether functions should be declared with function or var, it's a matter of personal style. I (personally) like function, but I know of many seriously talented JavaScript programmers who use var initializations.
About your 1st Question. What actually is happening that the variable Gallery is being assigned the value that your function is returning, which is basically undefined.
You are not able to do Gallery.helloworld() because .. Gallery is undefined.
The helloworld1() is not working as it would look for a helloworld1 function on the global object which is not defined again.
This is because you defined these functions inside the function scope.
You need to do this to achieve what you are trying to do.
var Gallery = function(){
return {
helloworld1:function(){alert('hey1')},
helloworld2:function(){alert('hey2')},
helloworld3:function(){alert('hey3')}
}
}();
This assigns Gallery to an object that has all the three functions as its properties. In this way then you can call. Gallery.helloworld1() which would print the alert.
This is a way of protecting an object from further modifications.
E.g you could do this
var Gallery = function(){
var realGallery = {no_of_pictures:1};
return {
getNumberOfPictures:function(){return realGallery.no_of_pictures;},
increasePictures:function(){realGallery.no_of_pictures += 1;},
decreasePictures:function(){realGallery.no_of_pictures -= 1;}
}
}();
This way no one can directly set no_of_pictures on realGallery object. They can only be incremented or decremented.
About your 2nd Question. It is generally not considered a good practice to use globals as anyone can tamper with them.
Lets say you defined function helloworld() {alert('hey1');}
Someone could easily redefine helloworld like this.
function helloworld(){alert('go away right now !!');}
So someone could easily completely break down your application with some small hack. That's why globals are considered a bad practice in javascript.
If you notice in the code that you cited, the parentheses after the Gallery function. Those are there to call the function immediately. So as soon as the code runs, that function is called. And that particular function is assigning the 3 hello world functions to their respective variables. But there is no access to those functions because o the reasons the first answer stated. So I'm not sure of the purpose of that code.
The key here is you have a self executing function, which doesn't return a value, therefore you can't access anything from within it, regardless of whether it was declared using var or this.
The goal of this coding style is to avoid polluting the global space with lots of variables and functions. Everything is encapsulated into the Gallery function. Using this style, you wouldn't try to access anything from the outside. It is like a bootstrap function where a set of procedures are executed and then it finishes, without the need to call anything inside again.
If you want to access from the outside, you need to first remove the self executing part, and secondly declare public properties or public pointers to the private properties:
var Gallery = function () {
var helloworld1 = function () {
alert('hey1');
}
var helloworld2 = function () {
alert('hey2');
}
var helloworld3 = function () {
alert('hey3');
}
this.helloworld1 = helloworld1;
this.helloworld2 = helloworld2;
this.helloworld3 = helloworld3;
};
var g = new Gallery();
g.helloworld1();
If you were to have the function return itself, then you can access the inside (providing the methods/properties are made public with this:
var Gallery = function () {
this.helloworld1 = function () {
alert('hey1');
}
return this;
}();
console.log(Gallery.helloworld2);
Related
I am looking to call a function that was originally just an anonymous function, but it turned out I need this function 3 times in my code.
So I defined a function like this:
function saveButton() {
this.parentElement.parentElement.querySelector('h3').innerHTML = this.parentElement.querySelector('input[name="task-title"]').value;
this.parentElement.parentElement.querySelector('p').innerHTML = this.parentElement.querySelector('textarea').value;
this.parentElement.parentElement.querySelector('.popup').className = 'popup hidden';
this.parentElement.parentElement.querySelector('.overlay').className = 'overlay hidden';
saveWork();
};
I want to call this function in an anonymous function like this :
confirmButton.onclick = function()
saveButton();
};
But afterwards I realized that I couldn't use the this in the anonymous function. How can I call confirmButton() in the anonymous function?
confirmButton.onclick = saveButton;
or
confirmButton.onclick = function(){
saveButton.call(this);
};
although it's not a good practice to have the same name for DOM node and a function that you want to call. rename your function into something that makes more sense like buttonClick
Have you tried using function expressions?
Essentially it means assigning a function to a variable.
Read this answer to learn about the differences between function expressions and function declarations.
As for your question, most of the time it's this case:
You want to use the parent scope of a given anonymous function.
If thats the case, I would recommend this neat little trick:
var self = this;
this.saveButton = function() { // or self.saveButton...
this.parentElement.parentElement.querySelector('h3').innerHTML = this.parentElement.querySelector('input[name="task-title"]').value;
this.parentElement.parentElement.querySelector('p').innerHTML = this.parentElement.querySelector('textarea').value;
this.parentElement.parentElement.querySelector('.popup').className = 'popup hidden';
this.parentElement.parentElement.querySelector('.overlay').className = 'overlay hidden';
saveWork();
};
confirmButton.onclick = function() {
self.saveButton();
}
This trick can be used in any level of scope depth, just don't pollute the global namespace :)
By looking at the code fragment you posted, and guessing a few things, I suggest the following refactoring:
function saveButton(parentElem) {
var myParent = parentElem || this.parentElement;
myParent.parentElement.querySelector('h3').innerHTML = myParent.querySelector('input[name="task-title"]').value;
myParent.parentElement.querySelector('p').innerHTML = myParent.querySelector('textarea').value;
myParent.parentElement.querySelector('.popup').className = 'popup hidden';
myParent.parentElement.querySelector('.overlay').className = 'overlay hidden';
saveWork();
}
confirmButton.onclick = function() {
// I suppose when this function is called somewhere else,
// you actually know who is the parent element, so:
saveButton(document.querySelector('.theParentElement'));
};
// If you calling it somewhere where "this" is available,
// then simply call the function with no arguments:
saveButton();
Maybe some variation of the example above can help you. Other than that, I can't think of a better answer without looking at a greater portion of your code.
I've the following javascript code
var globalConfiguration = null;
function loadFile(filePath) {
}
function onLoadPage() {
}
function getConfiguration() {
}
function process() {
}
I want to use IIFE to encolose all my functions in a closure to avoid cluttering the global name space,so I wrote :
(function(window){
var globalConfiguration = null;
function loadFile(filePath) {
}
function onLoadPage() {
}
function getConfiguration() {
}
function process() {
}
});
However, I do not understand this notion very well, now in my HTML page how would I call my function onLoadPage?
You can't without putting it in the global namespace somehow.
My recommendation to structure code like this:
function ExampleHelper() {
(function(scope) {
scope.globalConfiguration = null;
scope.loadFile = function(filePath) {
};
scope.onLoadPage = function() {
};
scope.getConfiguration = function() {
};
scope.process = function() {
};
})(this);
}
var foo = new ExampleHelper(); // "foo" now contains all of your functions
foo.onLoadPage();
Now that you have enclosed the module, you need to decide what you want to expose to the outside world. Anything you want to expose, you can export. Also, you need to decide what context (in this case, window) that you want to attach to. Then pass the context in right away (thus completing the IIFE).
For example:
(function(window){
var exports = {};
var globalConfiguration = null;
function loadFile(filePath) {
}
function onLoadPage() {
}
function getConfiguration() {
}
function process() {
}
exports.getConfiguration = getConfiguration;
window.myModule = exports;
})(window);
Attaching to the passed in window object is one way to export things out in a controlled fashion. So, you do need to pass the context (in this case window) to the IIFE. Perhaps, window will not always be the context for the call.
After running this code, myModule will be available on the global scope.
You can set your function to window.onload callback.
(function(window) {
var globalConfiguration = null;
window.onload = onLoadPage;
function loadFile(filePath) {}
function onLoadPage() {
alert('hello world');
}
function getConfiguration() {}
function process() {}
}(window));
This is called chaining of functions/methods and is usually done for better readability of the code and to avoid the usage of temporary variables to hold the return value of each function.
Check this post on chaining methods which helped me to understand the chaining better.
I see you wanted to use closures to avoid cluttering the global object. However, do note that we write functions for reusability. Though you create a closure, ensure that your methods inside the outer function are abstracted such that they can be used by other parts of the code.
For ex: from your code, you have a loadFile method which could be reused.
Now to see how you can use the methods you described in a chain.
Assumptions: (since i don't know why you wrote those methods, i am making some assumptions).
loadFile(filepath) - returns a file object
onPageLoad() - once the page is loaded, it returns the object or id of the input file
getConfiguration() - gets the file path
process() - process the file
onPageLoad().loadFile(getConfiguration()).process();
The important part is that the scope of the object is set correctly in the chaining. In order to do this, each method must return the reference to appropriate object.
Hope this helps.
Is there any way to refer to the function object that you're currently executing in? If it's not a method of any object or not called with .call() or .apply(), the this pointer is likely just window, not the function object.
I often use a design pattern like this for global variables that I want scoped to a particular function as this keeps them out of the top level namespace:
function generateRandom() {
if (!generateRandom.prevNums) {
generateRandom.prevNums = {}; // generateRandom.prevNums is a global variable
}
var random;
do {
random = Math.floor((Math.random() * (99999999 - 10000000 + 1)) + 10000000);
} while (generateRandom.prevNums[random])
generateRandom.prevNums[random] = true;
return(random.toString());
}
But, I'd rather not have to spell out the function name every time I want to use a variable scoped to that object. If the name of the function ever changes, there are then a lot of places to change the name.
Is there any way to get the currently executing function object?
Well, you could use arguments.callee()...
https://developer.mozilla.org/en/JavaScript/Reference/Functions_and_function_scope/arguments/callee
From MDN:
Description
callee is a property of the arguments object. It can be used to refer
to the currently executing function inside the function body of that
function. This is for example useful when you don't know the name of
this function, which is for example the case with anonymous functions.
Note: You should avoid using arguments.callee() and just give every
function (expression) a name.
BUT...
What you really want are Javascript Prototypes.
function RandomSomethingGenerator()
{
this.prevNums = {};
}
RandomSomethingGenerator.prototype.generate = function() {
var random;
do {
random = Math.floor((Math.random() * (99999999 - 10000000 + 1)) + 10000000);
} while (this.prevNums[random])
this.prevNums[random] = true;
return(random.toString());
};
Why do I say this?
1.) You're dirtying the global space with all those functions.
2.) Even if you like Jani's suggestion, and you want a "static" function like you have now, my suggestion would be the same, but with a twist: Create your global function, and wrap an instance of an object (built from a prototype) inside the closure and make the call to it (so, basically, make yourself a singleton).
As in this (adapted from Jani's answer):
var randomSomething = (function() {
var randomSomethingGenerator = new RandomSomethingGenerator();
return function() {
randomSomethingGenerator.generate();
};
})();
I don't think there's any way to do exactly what you ask, but you could use a closure for your function-local static variables instead.
You can easily achieve this using an IIFE:
var generateRandom = (function() {
//any function's static variables go here
var prevNums = {};
return function() {
//function code goes here
var random;
do {
random = Math....
}
prevNums[random] = true;
return random.toString();
};
})();
You want arguments.callee. From MDN - callee:
callee is a property of the arguments object. It can be used to refer to the currently executing function inside the function body of that function. This is for example useful when you don't know the name of this function, which is for example the case with anonymous functions.
For example:
> foo = function() { console.log(arguments.callee); };
> bar = function() { foo() };
> bar();
function () { console.log(arguments.callee) }
However, I think this is being deprecated. The above link says, "The 5th edition of ECMAScript forbids use of arguments.callee() in strict mode."
Is there any way to break a closure easily in JavaScript? The closest I have gotten is this:
var src = 3;
function foo () {
return function () {
return src; }
}
function bar (func) {
var src = 9;
return eval('('+func.toString()+')')(); // This line
}
alert(bar(foo()));
This prints '9', instead of '3', as a closure would dictate. However, this approach seems kind of ugly to me, are there any better ways?
Your code is not breaking the closure, you're just taking the code the makes up a function and evaluating it in a different context (where the identifier src has a different value). It has nothing at all to do with the closure that you've created over the original src.
It is impossible to inspect data that has been captured in a closure. In a sense, such data are even more "private" than private members in Java, C++, C# etc where you can always use reflection or pointer magic to access them anyway.
This could be useful if you are trying to create multiple similar methods in a loop. For example, if you're creating a click handler in a loop that relies on a loop variable to do something a little different in each handler. (I've removed the "eval" because it is unnecessary, and should generally never be used).
// Assign initial value
var src = 3;
// This is the regular js closure. Variables are saved by reference. So, changing the later will
// change the internal value.
var byref = function() {
return src;
}
// To "break" the closure or freeze the external value the external function is create and executed
// immidiatly. It is used like a constructor function which freezes the value of "src".
var byval = function(s) {
return function() { return s };
}(src);
src = 9;
alert("byref: " + byref()); // output: 9
alert("byval: " + byval()); // output: 3
As others said this doesn't seem to be the right thing to do. You should explain why you want this and what you want to achieve.
Anyway, one possible approach could be to access properties of an object inside your function. Example:
var src = 3;
function foo (context) {
context = context || window; // Fall back to the global namespace as default context
return function () {
return context.src;
}
}
function bar (func) {
var context = {src: 9};
return func(context);
}
alert(bar(foo));
If you want to access a variable in a wider scope, just don't reuse the variable name in a narrower scope.
That's how it is supposed to work. Work with it instead of trying to fight it.
Here is the code see if you can understand , closures defined within a loop .
var clicked = false;
for(var i=0;i<temp.length;i++){
(function(index){
if(clicked) return false;
$(temp[index]).on('click',function(){
if($(temp[index]).text()=="" && !$(".cell1").val()){
$(this).text(player1Val);
$(".cell1").val(true);
console.log("first player clicked ");
clicked = true;
$(this).off();
for(var j=0;j<temp.length;j++){
$(temp[j]).off('click');
}
return false;
}
else return false;
});
})(i);
}
How can i call a YUI function that is wrapped inside a YUI().use from javascript?
example
Below is a YUI function "runShowAnim" which executes animShow.run(); for an animation effect...
var runShowAnim = function(e) {
animShow.run();
};
I want this effect to happen when i validate something in a javascript function. I tried to call it as below. But it doesn't seem to work.
function notifyUser(message) {
document.getElementById("msgArea").innerHTML = message;
runShowAnim();
}
I achieved this by sandwiching the YUI function completely inside a function and calling that function..
var runShowAnim = function() {
YUI().use('anim', 'node', function(Y) {
var animShow = new Y.Anim({
node: '#msgArea',
to: { height: 50,opacity:1 }
});
animShow.run();
});
};
now i can call runShowAnim without any problem like in the below sample function..
function notifyUser(message) {
document.getElementById("msgArea").innerHTML = message;
runShowAnim();
}
If you want to call a function, you have to suffix the function name with () and include 0 or more comma separated arguments between them.
runShowAnim();
If the function doesn't have global scope (as yours will have if it is declared inside a function passed to use()) and not passed outside in some way then you can only do this from the same scope.
I think you're missing the parentheses.
function notifyUser(message) {
document.getElementById("msgArea").innerHTML = message;
runShowAnim(); // right here
}
YUI.thefunction()?
I think you need to call it with namespace too
something similar to
var X = function(){};
X.Y = function(){};
X.Y.Z = function(){};
X.Y.Z.foo = function(e){alert(e);}
//foo("me");<-error
X.Y.Z.foo("me");
If you want to call a function that has been defined inside the closure (the function passed as the last parameter to YUI.use) from outside it, you need to expose the function globally.
Either define a global variable outside the closure and assign your function to it, or assign your function to the window object
i.e.
var runShowAnim;
YUI().use(function(e){
runShowAnim = function(){alert('called');}
});
runShowAnim();