October 14, 201412 yr Those of us familiar with javascript know we should not be polluting the global scope with variables, I'm just wondering what the best method is as I use quite a few in various places, all seem to work but I'd be interested to know what others think is the better method. 1. Using an object with the function as a method. var scope1 = { init: function(){ // Variables here are only scoped to this objects init method } }; scope1.init(); 2. using a declared function function scope2(){ // variables here are scoped to this function only } scope2(); 3. using an immediatley invoked function expression (IFEE) (function scope3() { // variables here closed to this function scope. }());
October 14, 201412 yr In terms of polluting the global scope, it has to be no 3. Both 1 & 2 are still attached to window.Personally I also use all three, along the lines of: var App = (function($, w, d, undefined) { // private variables and functions var privateVariable; function privateFunction() { // do something } return { // public variables and functions init: function() { this.publicFunction(el, opts); }, publicFunction: function(el, opts) { el.privateFunction(); } }; })(jQuery, window, document); App.init(); Edited October 14, 201412 yr by Wynn
October 15, 201412 yr Author The issue I have with 3 is it cannot be recalled again after execution (unless I am missing something?). At the moment I use number 3 to wrap all the code I write for a project as that will only need to be called once and immediately then all other functions that I write like equal heights or lazy loading each go inside their own object with an initialization method. Be interesting to see what others are using too
October 15, 201412 yr Author In terms of polluting the global scope, it has to be no 3. Both 1 & 2 are still attached to window. Personally I also use all three, along the lines of: var App = (function($, w, d, undefined) { // private variables and functions var privateVariable; function privateFunction() { // do something } return { // public variables and functions init: function() { this.publicFunction(el, opts); }, publicFunction: function(el, opts) { el.privateFunction(); } }; })(jQuery, window, document); App.init(); This forms the barebones skeleton if you will that all (properly written) jQuery plugins doesn't it? And correct me if I'm wrong but this example is also making use of closure, something I didn't touch on in my examples. Something I've recently learned and should start making more use of it in my applications. Edited October 15, 201412 yr by rbrtsmith
October 15, 201412 yr It's a standard module pattern, yes it's used in jQuery plugins. The IIFE keeps everything closed to the outside but you can return whatever methods / variables you like to give you future access to them.
October 20, 201412 yr Interesting discussion. That article is a good read, thanks Wynn. I've always used the namespace method (method 1) or constructor functions and inheritance with prototype. Never used the IIFE method although I see it's uses and should probably use that more.
October 21, 201412 yr Author In terms of polluting the global scope, it has to be no 3. Both 1 & 2 are still attached to window. Personally I also use all three, along the lines of: var App = (function($, w, d, undefined) { // private variables and functions var privateVariable; function privateFunction() { // do something } return { // public variables and functions init: function() { this.publicFunction(el, opts); }, publicFunction: function(el, opts) { el.privateFunction(); } }; })(jQuery, window, document); App.init(); Quick question on this Wynn, what is the undefined parameter for in the App IIFE
October 21, 201412 yr Basically undefined is mutable, somebody can change it (undefined = true), by passing in an extra undefined parameter, then undefined === undefined in the local scope no matter what it equals in the global. Edit: undefined was mutable, it's been fixed in ES5. So that's only true for older browsers. Edited October 21, 201412 yr by Wynn
October 21, 201412 yr Author Ok I understand now, thanks! ES5 is compatable with IE9 upwards isn't it? Been reading a few things about ES5 like object.create which looks nicer than using the new keyword alternative
October 21, 201412 yr Author Interesting discussion. That article is a good read, thanks Wynn. I've always used the namespace method (method 1) or constructor functions and inheritance with prototype. Never used the IIFE method although I see it's uses and should probably use that more. Agreed! I've started using it more since reading To expand on Wynns Example module with his App IIFE do you guys also nest further IIFEs inside e.g. I could see this being useful if multiple devs are working on a single application and each wanted their own modules closed off. var App = (function($, d, w, 'undefined'){ // private stuff return { init: function() { var module1 = (function(){ // stuff thats private to module 1 return { init: function(){ // available to App } }; }()); module1.init(); var module2 = (function(){ // stuff thats private to module 2 return { init: function(){ // available to App } }; }()); module2.init(); } }; }(jQuery, window, document)); App.init(); Edited October 21, 201412 yr by rbrtsmith
October 22, 201412 yr Like any other design pattern, the IIFE has its pro's and con's. There's no reason they can't be nested, but frequently it's unnecessary. In terms of working with multiple devs, the issue that the pattern you displayed (other than the SyntaxError - I'll get to that) is that many people will be trying to modify the same code. That will cause headaches at best and merge collisions at worst.A better solution would be to collate multiple files all referencing a common namespace. Each developer would work in his or her own file, and an IIFE for each part of the code would keep scope contained. It would look something like this: // Base file var MYAPP = {}; // Dev 1's file MYAPP.module1 = (function () { return { }; }()); // Dev 2's file MYAPP.module2 = (function () { return { }; }()); Modules would either be started manually or using some kind of autoloader. This pattern gained popularity when it got the name The Yahoo Module Pattern and it's still widely used today.Now - that SyntaxError I mentioned. Your first line looks like this: var App = (function($, d, w, 'undefined'){ The string 'undefined' should be an argument name. The first line should look like this: var App = (function($, d, w, undefined){ It's worth pointing out that in 5 or 6 years of professional JavaScript writing, I have never seen anyone write var undefined = true;
October 23, 201412 yr Author I'm astounded there was only one syntax error there, I just merely typed the lot into the code window here ha! Thanks your reply, that does make sense actually. We use grunt concat coupled with uglify we could impliment this methodology quite easily. I was just thinking along the lines of keeping the whole app encapsulated but I guess that is not really essential. I was thinking it's highly unlikely somebody would re-define undefined but I guess we have to protect against some weird edge cases, perhaps from malicious scripts? I just see on Crockford's videos that he's always banging on about not using certain parts of the language because of edge case scenarios, how likely are they to happen? He knows a hell of a lot more than me though so I'm happy to go along with what he suggests! Thanks for your input Skateside. I've only been coding Js for under 2 yrs so it's good to hear from somebody with more experience (You too Wynn ) Edited October 23, 201412 yr by rbrtsmith
Create an account or sign in to comment