I have a file called bbUI.js which contains this bit of JavaScript. Outside of that file, I'd like to be able to call "var x = new iScroll(...)", but I currently get the error "ReferenceError: Can't find variable: iScroll".
(function(){
var iScroll = function (el, options) {
var that = this,
doc = document,
i;
// More code
};
})();
From what I can tell, iScroll is defined within an anonymous function, and is itself anonymous but assigned to the identifier iScroll. If that's accurate, should I be able to call "var x = new iScroll(...)" in other places in my code?
The iScroll function only exists within the scope of the anonymous function it's wrapped in. To use it elsewhere, you need to make it global.
You can make it global by removing the function it's wrapped in, or by setting window.iScroll = iScroll inside the anonymous function.
Remove the anonymous function that wraps the code:
(function(){ // <- this
...
})(); // <- this
The anonymous function prevents that code from polluting the global variables, so iScroll is defined only within that anonymous function.
Answer to this question depends on what do you really want to achieve and what the purpose of a self executing function. Anyway.. here iScroll is inside the self executing function and you have to make it available in the scope outside. I have given below two methods to do this.
Either just make it global by removing var keyword
(function(){
iScroll = function (el, options) {
var that = this,
doc = document,
i;
this.show = function(){
alert("hello world");
}
};
})();
or by adding a variable iScroll externally and returning the function.
var iScroll = (function(){
return function (el, options) {
var that = this,
doc = document,
i;
this.show = function(){
alert("hello world");
}
};
})();
to test
var iscroll = new iScroll();
iscroll.show();
Another option could be the following:
var iScroll = (function(){
var iScroll = function (el, options) {
};
return iScroll; // <-- add this line
})();
Related
I have an IIFE that I am trying to make into a bookmarklet. I would like to have the modal the bookmarklet will pop up have some buttons that will call a function. However, when I have a structure like this:
(function(){
var __myFn = function(str){ //also have tried function __myFn(){..}
alert(str);
}
//some AJAX that builds HTML with the `result`s
document.getElementById("resultDiv").innerHTML = "<span onclick='__myFn(" + result.someData+ ")'>test</span>
}());
I get Uncaught ReferenceError: __myFn is not defined
How can I make this function recognized? Is there another way?
When you use the var keyword, you're creating a variable that is local to the scope of the enclosing context. Since the enclosing context is a function, __myFn is local to the function itself and not known outside (i.e., not known in the global context).
If you want to use something that is inside, you would have to return a reference to it. You can use something like the module pattern for this:
var myModule = (function(){
var __myFn = function(str) {
alert(str);
}
return {
myFn: __myFn
};
})();
Then you can do:
//some AJAX that builds HTML with the `result`s
document.getElementById("resultDiv").innerHTML = "<span onclick='myModule.myFn(" + result.someData+ ")'>test</span>
However, I recommend not binding your event handler this way. Use jQuery or use DOM methods (addEventListener) to bind event handlers. This way you could even do it inside the IIFE itself, which means you don't even have to return something from the IIFE. This means your global context is not polluted. Right now, the only reason you have to return something from the IIFE is because you are binding an event-handler inline via HTML.
Here are two examples. The first one assumes that the IIFE returns a reference to __myFn:
var resultDiv = document.getElementById("resultDiv");
resultDiv.addEventListener("click", myModule.myFn, false);
Here is the second example that does it within the IIFE itself:
(function(){
var __myFn = function(str) {
alert(str);
}
var resultDiv = document.getElementById("resultDiv");
resultDiv.addEventListener("click", __myFn, false);
})();
For reasons I don't understand, I have found that taking the "var" off the declaration makes it work.
Example 1 (fails):
(function() {
var counter = 0;
var init = function() { console.log("init called"); }
})();
init(); // regardless of whether I named the function or not, this fails.
HOWEVER:
Example 2 (works):
(function() {
var counter = 0;
init = function() { console.log("init called"); }
})();
init(); // this calls the function just fine.
Note you can add any number of functions inside the iife this way just fine.
I have a question about whether or not what I'm attempting is possible in Javascript in regards to closures and parent scopes. Here's my code:
var func1 = function() {
// console.log(this.source1); // wont work, makes sense
// console.log(source1); // wont work, wish it would
console.log(this.source2); // works fine
console.log(source2); // works fine
};
var func2 = function() {
var source1 = "source1";
this.source2 = "source2";
func1.call(this);
}();
var func3 = function() {
var source3 = "source3";
var func4 = function() {
console.log(source3); // also works fine, makes sense
}();
}();
Is there any way I can get access to variables declared with var on func2 inside func1, or am I out of luck?
As others have said -- no.
But if you put this whole thing in a wrapper and use the Revealing Module Pattern, then you can.
var module = (function() {
var source1;
var source2;
var func1 = function() {
console.log(source2); // works fine
};
var func2 = function() {
source1 = "source1";
}();
var func3 = function() {
var func4 = function() {
console.log(source1); // also works fine, makes sense
}();
}();
return {
func1: func1,
func2: func2,
func3: func3
};
}());
// Then invoke them.
module.func2();
module.func1();
EDIT
Then you can re-assign them back to the original names.
var func1 = module.func1;
var func2 = module.func2;
var func3 = module.func3;
Well, no, it won't work, and it shouldn't. Thankfully :) That's exactly how local variables are supposed to behave.
One thing you can do is pass the desired variable to the function func1 (and the function should expect it. Which is no problem — if you wish to somewhere call this function without passing a variable, Javascript would be totally okay with it)
Another thing is to declare the source1 variable without "var" keyword. Then it would work, but you really shouldn't do that unless you're keeping a very good track of your global variables.
The answer to your question is no.
The scope of the inner function is limited to its own scope and the scope of the outer function in which the inner function is declared (not called but declared).
console.log(this.source2); works fine cause both function have window as their context (window plays role of the outer function). this = window inside those functions.
I am currently writing all javascript functionality of a certain page in JQuery's document.ready handler:
$(document).ready(function() {
var one, two, three;
function f1(par1) {}
function f2() {}
...
});
I feel that this isn't optimal or according to Javascript best practices. What I need is a private scope for the page's functionality, nothing needs to be called externally.
I've seen a number of different ways:
jQuery source
(function(window) {
var anObj = {};
...
window.functionality = anObj;
}(window));
A function that is self-invoked with the window as parameter, then setting the functionality object of your application on it.
Codemirror source
window.functionality = (function() {
var functionality = {};
...
return functionality;
}());
Very similar to what jQuery does, but setting the functionality object indirectly on window by making a self-invoking function return something first.
This question
var functionality = {};
(function(obj) { obj.f1 = ... }(functionality));
Creating a local variable (instead of on window), and setting its content inside a self-invoked function (why?)
How do I declare a namespace in JavaScript?
var functionality = {
f1: function(){},
f2: function(){}
}
Pretty much the same as the previous thing but setting the contents without a self-invoking function (again why use or not use the self invoking function?).
So... which way is best?
I would suggest the module pattern for this, where a page is treated as a module. There is a lot of information about the javascript module pattern on the web. Have a look at http://www.adequatelygood.com/JavaScript-Module-Pattern-In-Depth.html.
I've used an example from the link and modified it a bit:
var MyApp = MyApp || {};
MyApp.PageX = (function () {
var my = {},
privateVariable = 1;
function privateMethod() {
// ...
}
my.moduleProperty = 1;
my.moduleMethod = function () {
// ...
};
return my;
}());
What is happening here, is that a set of properties and methods is defined and namespaced to MyApp.PageX, MyApp being the global. So this will work:
MyApp.PageX.moduleProperty; // 1
MyApp.PageX.moduleMethod();
What I want to do is to execute the create_tag function when a specified condition is satisfied. I am referring to this function as a method of an object, in this case document.body, by setting as its method an external function, "create_tag(..)". The problem is inside this function I have a "this" keyword which I would expect to refer to the method's parent, document.body. Instead it doesn't seem to work. I tried replacing "this" with "document.body" in the function so the problem should be caused by "this".
Here is the code:
xmlDom=xmlhttp.responseXML;
hint_ul=document.getElementById("hint_ul");
personaggi=xmlDom.documentElement.getElementsByTagName("personaggio");
for(i=0;i<personaggi.length;i++){
personaggio=personaggi.item(i);
name=personaggio.childNodes[1].firstChild.nodeValue;
if(name.substr(0, str.length).toLowerCase()==str.toLowerCase()){
document.body.crea_li=create_tag(name);
}
}
}
function create_tag(inner){
a=document.createElement("a");
a.innerHTML=inner;
this.appendChild(a); }
this will be window when called like that.
To get its this as the body element, call it like so...
document.body.crea_li = create_tag.call(document.body, name);
Nowhere in your code is create_tag assigned as a method of document.body. The closest you get is with the line document.body.crea_li=create_tag(name);, but what's actually happening here is that you are executing create_tag as a member of the global object, and the result of that operation is assigned to document.body.crea_li.
You could make a reference to this outside the function body - referencing it within the scope later:
var self = this;
function create_tag(inner){
a=document.createElement("a");
a.innerHTML=inner;
self.appendChild(a);
}
This could be a nice trick. When I make complicated javascript objects involving many objects and functions, at the top of the object I create:
var self = this;
as that will live within the scope, the root object is always accessible.
Here is a working example of how I would implement this:
SomeReallyComplexThing = function() {
var self = this;
var foo = 'bar'
this.fooThing = 'Other thing'
this.setSomeData = function(){
console.log('Some data set', arguments)
}
this.makeMassiveCall = function() {
var completeFunc = function(){};
var url = '/some/endpoint.json';
var requestData = {};
jQuery.get(url, requestData, function(data) {
/*
* Data has come back
*/
self.setSomeData(data)
completeFunc(data);
});
}
}
//outside the scope
s = new SomeReallyComplexThing()
s.fooThing() //visible
s.self //undefined
this in javascript is a sqirrely fellow. The idea is this refers to the current function context.
This means that when your running code inside the function this refers to that function's context, which does not have an appendChild method.
Normally you use a closure to keep a reference to the calling context around, something like this
var _self = this;
var result = func();
function func()
{
// _self is the calling context, this is the current context
}
Or you could pass a reference to the calling context:
document.body.crea_li=create_tag(name,this);
function create_tag(inner, context) { context.body.appendChild(...) }
this is referring to the function's parent, but its parent is actually the window object, not the document object or document.body. this actually refers to wherever context the function is called from, and in my opinion you should avoid using it to call methods just for that reason because it can be difficult to see what this is actually referring to. For example, if you called a function using this from another function, it would refer to the context within that function.
This example might help show what's going on:
var hello = function() {
alert( this.message );
}
window.message = "hello!";
hello()
You could document.body directly in the code like you suggested before, or you could pass another parameter that tells the function where to append the created tag:
function create_tag(inner, elementToAddTag){
a=document.createElement("a");
a.innerHTML=inner;
elementToAddTagTo.appendChild(a);
}
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();