I'm trying to wrap a JavaScript object literal in a self executing anonymous function. The first code example below works fine, but the second doesn't and I'm not really sure why?
Works:
(function(){
return MyApp = {
init: function() {
console.log('MyApp init');
}
}
})();
Doesn't Work:
(function(){
var MyApp = {
init: function() {
console.log('MyApp init');
}
}
return MyApp;
})();
As I understand things, the SEAF should execute and immediately return. That's why the first example returns MyApp as an object I can interact with. I thought assigning MyApp to a variable inside the SEAF and then returning it would do the same thing but in:
Uncaught ReferenceError: MyApp is not defined
Why?
Since the result of your SEAF (better named IEFE) is not used anywhere, it doesn't really matter what the function returns. Now compare
(function(){
MyApp = {…}
})();
with
(function(){
var MyApp = {…}
})();
The difference is that in the second function your variable is preceded by a var keyword which makes it local to the IEFE, while in the first function it is an implicit global (which you should avoid). That way, the second snippet doesn't assign to anything in the global scope, and accessing MyApp later from outside will fail with the error.
Better return some value that you then assign to a globally declared variable:
var MyApp = (function(){
return {…};
})();
What your first example is doing is setting MyApp as a global variable - since the variable MyApp is not preceded by a var keyword or dot notation, it becomes global. It sounds like that's not actually an issue for you if you're putting MyApp in a self-executing function - you can really just remove the return statement from it - or even define other globals in the same function. You don't ever reference the result of your top-level function, so there's no use of that return.
Your second example sets MyApp as a local variable using var, so it's visible only inside of the context of the function that's running it.
Solution using arrow functions:
var myApp = (() => {
return {
init: () => console.log('MyApp init')
};
})();
myApp.init();
Explanation:
The global variable myApp is set to the result of an IIFE (Immediately-invoked Function Expression).
init can also be written as an arrow function.
If no other logic is performed in an arrow function before the return statement, and it returns an object literal, it can be further simplified. To return an object literal from an arrow function, wrap it in parentheses:
var myApp = (
() => ({
init: () => console.log('MyApp init')
})
)();
Related
I am creating some basic plugin and i am getting Reference error. Below is my code
jQuery.fn.validate = function(options) {
var _self = this;
// with below call I gets reference error.
abc();
//but if call in below it works fine
_self.on("submit", function(event) {
abc(); // works fine
}),
abc = function () {
console.log('here);
}
};
Can someone explain why I am getting this error and how to overcome it. As i need to call some reset and init functions at the begining of the plugin.
It seems like you're expecting abc to be hoisted, but you're specifically using a syntax that leaves abc undefined until the assignment is executed.
You need to move abc = function ... up above the invocations of abc(), or define the function using function abc() { } which will allow it to be hoisted above your invocations.
Note that, if you simply move the assignment, you should use var abc = function ... and create a local variable, rather than the global abc variable you're currently creating.
I have been writing javascript for a while now and more recently been playing with coffeescript. I noticed that coffeescript compiles functions in the following way:
(function() {
}).call()
I have also noticed people write functions in this way:
(function() {
})()
From what I understand these are anonymous functions that call themselves. Firstly, what is the difference in between having .call() and just () is .call() just a more semantic way of writing ().
Also why does coffeescript wrap the entire file in an anonymous function, when it isn't usually necessary? Are there any performance or other advantages to this? When should these sort of self calling anon functions be used?
Thanks
Using .call() changes the context of the IIFE to the this value of the parent scope.
The first this will be [object Window], the global scope in browser environments:
(function () {
console.log(this);
})();
The second, will be the exact same:
(function () {
console.log(this);
}).call(this);
The difference is that in ECMAScript 5's strict mode, the first example this will be undefined:
(function () {
'use strict';
console.log(this); // undefined
})();
However when using Strict Mode and .call(), this is again the global scope with the correct this context:
(function () {
'use strict';
console.log(this);
}).call(this);
Here's a jsFiddle showing this. The main difference is that the normal IIFE loses it's this context, some CommonJS platforms evaluate files with a specific this.
CoffeeScript does this to ensure that your code has the same this context as the scope where it's placed (the parent scope) - because functions don't normally inherit their this object from the surrounding context.
Using the pattern(s) above, you should wrap your function logic in there to avoid placing all your code in the global scope and having variable/naming conflicts, to which you can then create things such as Modules and return only the APIs that you need, for instance:
var Module = (function () {
'use strict';
return {
someMethod: function () {
// do something
}
}
})();
// call it:
Module.someMethod();
Each function creates it's own scope, so wrapping your blocks of code in these will protect your variable/function names from conflicting with eachother. We can also access "private" methods from within these closures:
var Module = (function () {
'use strict';
var _privateMethod = function () {};
return {
someMethod: function () {
_privateMethod();
}
}
})();
We would do this when we don't want the methods to be publicly accessible by our users too.
I have defined the following module globally:
var module = (function () {
console.log(this);
this.fn = function () {
console.log(this);
}
return this;
})();
http://www.quirksmode.org/js/this.html :
In JavaScript |this| always refers to the “owner” of the function we're executing, or rather, to the object that a function is a method of.
The first call to console.log logs Window as the value of this, and that I understand. But, so does also the second call to console.log.
Since this refers to the owner of the function, why does module.fn log Window and not module?
When I call fn I still have to write module.fn, I can't write Window.fn. Since this refers to Window I find this confusing.
EDIT: I forgot to return this in my example.
Since this refers to the owner of the function, why does module.fn log Window and not module?
The return value of the outer function is window because it doesn't get called in any particular context, so module ends up being window as well.
It seems that the way you have applied the module pattern is wrong. It should be returning the public interface that gets used in the rest of your code:
var module = (function () {
console.log(this);
// public interface
return {
fn: function () {
console.log(this);
}
}
})();
module.fn(); // "Object {fn: function}"
In your example, the global object receives the fn. It is the window object in case of browsers. That is because you are calling the function in place (effectively constructing a new scope) without specific context.
On the end, your module object is just a reference to the window (because of return this;).
What is this?
In JavaScript, this is the current context, the object on which the function was called that particular time. It is not the "holder" of the function. You can always "steal" the method from other objects and apply (literally) it to your own.
Assume you want to slice the arguments object for some reason. It looks just like an array, but it is NOT an array. arguments.slice(2,4) does not work (assuming ECMAScript < 5). What to do?
Array.prototype.slice.apply(arguments, [2,4]);
You need to steal the slice function from the Array prototype, and use if on your arguments. Inside the slice call, the "this" is the arguments object that particular time.
How to construct a valid module?
Your job is to return the module object. You do not want do mess with the context. It is not relevant, as long as you are not applying the function directly on module object.
The easiest solution is the simplest.
var module = (function() {
// do something internally, great for "private" stuff
// then return the "public" interface
return {
doSomething: function() {
// do something
},
introduce: function() {
console.log(this);
}
};
})();
module.introduce(); // Object {doSomething: function, introduce: function}
module.doSomething();
The other way.
Alternatively, you could use the this to do your job, using the apply, if you really want to.
var module = {};
(function(){
this.doSomething = function() {
// do something
};
this.introduce = function() {
console.log(this);
};
}).apply(module);
module.introduce(); // Object {doSomething: function, introduce: function}
module.doSomething();
Note this is almost equal to the "new" call.
There are more equally valid ways to do it, but the first presented one is frequently used and very clear. Anyway, everything really depends on your code conventions.
Your pattern is wrong what you are doing to make a closed scope and setting module to the return from that scope:
// This is the design pattern:
var module = (function () {
var module = {};
var localVar = 1;
module.moduleVar = 2;
module.fn = function () {
console.log(this);
}
return module;
})();
console.log(module.fn); // function() { console.log(this) ;}
console.log(module.moduleVar); // 2
console.log(module.localVar); // undefined
I have a massive javascript file with many function expressions. All of a sudden console gives me the following errors:
In IE
The value of the property 'myFunc' is null or undefined, not a Function object
In Firefox
TypeError: myFunc is not a function
This is how I call the function:
myFunc();
This is the function:
myFunc = function() {
//do stuff
}
This is happening on ALL function expressions. If I change one to a function declaration it works, but then will fail on some other function expression call inside of it. What the heck?
Possibility 1
If you are calling the function expression before it is defined, you will get this error. If you however turn it into a function declaration, the function declaration would get hoisted to the top of the scope, and could be called before or after the actual declaration occurs. So:
functionFoo();
var functionFoo = function() {
};
Will give this error, because you are trying to call the function before it is defined. But:
functionFoo();
function functionFoo() {
}
Will work, because actual function declarations are hoisted to the top of the scope, and can be used anywhere.
Possibility 2
If you are calling the function expression from a different scope that is outside where the function expression is defined, you will get this error. function expressions, like other variables, can only be used within the scope they are defined. So:
$( document ).ready( function() {
var functionFoo = function() {
};
} );
functionFoo();
Will give you an error, because the defining of the function happens in a different scope than the call. But:
$( document ).ready( function() {
var functionFoo = function() {
};
functionFoo();
} );
Will work just fine, because both the defining and the call happen in the same scope.
My basic setup is a whole heap of Javascript under an anonymous self-invoking function:
(function () {
...
})();
My problem is that I can't seem to get access to the objects within this ASI function via the DOM tab. I tried both the following:
var MYAPP = function () {
...
};
var MYAPP = (function () {
...
})();
The first didn't fire at all. The second just said MYAPP is undefined in the DOM tab.
Is there a way around this?
In your first version, you are simply creating a function with the name MYAPP, but you are not executing it.
In the second version, your function is executed and its result is assigned to MYAPP. But your function does not seem to return anything, so MYAPP stays undefined.
See A Javascript Module Pattern on YUIBlog for an explanation of this pattern. Their example goes like this:
YAHOO.myProject.myModule = function () {
return {
myPublicProperty: "I'm accessible as YAHOO.myProject.myModule.myPublicProperty.",
myPublicMethod: function () {
YAHOO.log("I'm accessible as YAHOO.myProject.myModule.myPublicMethod.");
}
};
}(); // the parens here cause the anonymous function to execute and return
So your function basically returns an object containing all the public members. You can then access these with Firebug, too.