Could you explain to me what is the difference between that two approaches (FirstModule and SecondModule:
var MyModule = (function () {
return {
method: function () {
console.log("MyModule:method");
}
}
})();
var FirstModule = (function () {
return {
test: function () {
MyModule.method();
}
}
})();
var SecondModule = (function (myMethod) {
return {
test: function () {
myMethod.method();
}
}
})(MyModule);
In both cases we have the same object, it isn't a copy. I would be grateful for any good information, advantages, disadvantages of any approach.
The first approach uses the MyModule variable, which can be overwritten by other code, outside the module, after the FirstModule value has been asigned.
The second uses the myMethod variable, which can't (although properties of the object assigned to myMethod still can because that object is still globally available via the MyModule variable).
Related
I'm start learning Vue.js and ECMA6 syntax, I saw this in the tutorial:
methods: {
someMethod: function() {
console.log(this) // this works
}
}
Then I thought the syntax could be:
methods: {
someMethod: () => {
console.log(this) // this undefined
}
}
but this works:
methods: {
someMethod () {
console.log(this) // this works
}
}
Can explain the difference and the ECMA5 syntax?
Of your three options, only the first one is supported in ES5. The other two are additions in ES6.
The third option is an ES6 shortcut for the first option and thus they work identically in ES6.
When you use the arrow syntax as in the second one, this is NOT set to be the host object as it is in your first and third. That's one of the features of the arrow syntax and thus it should not be used when you expect this to be set to the host object. Instead, this will be set to the lexical context from where the code was defined - often referred to as "the value of this in the enclosing context" or the "lexical value of this" which in your case would be whatever this was when the host object was initially declared which apparently was undefined.
Here's a good reference article on arrow functions: ES6 In Depth: Arrow functions
Object methods that has method someMethod. In this case this is a link to object methods.
Object methods that has property someMethod that stores some anonymous function. In this function this is undefined because function is anonymous.
Object methods has internal function someMethod. In this function this is link to methods, because it's internal named function (not anonymous or external) of this object.
Good luck!
+ Try this way
var methods1 = function() {
var self = {
someMethod: function() {
console.log(self);
}
};
return self;
}();
var methods2 = function() {
var self = {
someMethod: () => {
console.log(self);
}
};
return self;
}();
var methods3 = function() {
function someOtherMethod() {
console.log(self);
}
var self = {
someMethod: function() {
someOtherMethod();
}
}
return self;
}();
methods1.someMethod();
methods2.someMethod();
methods3.someMethod();
Which one do you prefer and what are pros & cons one over another ?.
Personally i found singleton hard to read and maintain, a lot of context changes(this), always ends with caching right context through var self = this (or some proxy like $.proxy) + i will always have one global variable(singleton), while in second approach i can avoid creating global variable if module doesn't need to expose any API.
Simple example: (User click on "add to cart", some ajax get triggered and on success html(notification) is created)
Html
<div class="cart">
Add to cart
</div>
Module pattern
Not truly module pattern by definition, because i'm not returning anything from it, click handler can access outer scope via closure.
;(function(window, $, undefined) {
function constructHtml(data) {...}
function addToCart(product_id, quantity) {
...
$.ajax({
...
success: function(data) { constructHtml(data); }
});
}
$(function() {
var $addBtn = $('div.cart a');
var productId = $addBtn.data('product-id');
$addBtn.click(function(e) {
e.preventDefault();
addToCart(productId);
});
});
})(this, jQuery);
Singleton - Object literal(same example)
var Cart = {
settings: {
$addBtn: $('div.cart a'),
productId: $('div.cart a').data('product-id')
},
init: function() {
this.bindUiActions();
},
bindUiActions: function() {
var self = this;
this.settings.$addBtn.click(function(e) {
e.preventDefault();
self.addToCart(self.settings.productId);
});
},
addToCart: function(product_id, quantity) {
...
var self = this;
$.ajax({
...
success: function(data) {
self.constructHtml(data);
}
});
},
constructHtml: function(data) {...}
};
Cart.init();
While Singleton vs. Module Pattern can be a legitimate question, with the example you gave, this question should be reworded as Singleton vs IIFE, as it's not the module pattern per se, but rather the IIFE that the module pattern is wrapped in that is keeping cruft out of your Cart singleton. And even then, it's not a vs. kind of question -- both IIFE and Singleton can be used together. The purpose of the IIFE is just to keep stuff out of global scope.
So ..., you can package your singleton Code into an IIFE as follows
;(function(){
var Cart = {
settings: {
// Your code ...
};
Cart.init();
})();
In this case, you're writing your code as a Singleton but wrapping it in an IIFE, and there is no usage of global scope. The IIFE is completely independent of how you choose to write and organize your code. You would need a different example for a Singleton vs. Module Pattern question.
IIFE (immediately invoked function expression):
(function() {
console.log('run this in your browser console')
})()
Module pattern:
var module = (function () {
var privateScopeVar = 1 // scope of the IIF
// the 'this' context in this scope is the global object (e.g. window)
// returns literal object who's method's scopes are lexically bound
// to the IIF scope
return {
publicMethod: () => privateScopeVar // publicMethod scope can access IIF scope
}
})()
Singleton Literal + Singleton Literal that cannot be overwritten if included/imported more than once in EcmaScrip5:
var singleInstance = { firstName: 'Greg' }
var singleInstance = singleInstance || { firstName: 'Greg' }
Singleton Literal that cannot be overwritten or initialized more than once in EcmaScrip6:
const singleInstance = {
firstName: 'Greg',
called: false,
init: () => {
if (!this.called) {
console.log('only once')
this.called = true
}
}
}
// of course singleInstance.called = false; singleInstance.init() is always possible
Singleton inside IIF (provides private state)
const singleton = (function () {
// IIF private scope ensures there is a single instance ever
var storedInstance
// Also some private state for the singleton instance as well
const firstName = 'Greg'
// literal object that holds constructor function
const Singleton = {
getInstance: () => {
if (!storedInstance) {
storedInstance= {
getName: () => firstName
}
}
return storedInstance
}
}
return Singleton
})()
I am a little confused here. Following the module pattern in JS, a module is normally a returned object from an anonymous function that is immediately executed. But what if I don't want to execute the function and instead call it whenever I need to e.g. window.onload.
var module = function (args) {
//private members
return {
//public members
};
};
var module_instance = module (args); // module instance or facade instance?
Are there any problems with this implementation? Is there a different, more efficient way to do this?
Also, following the previos block of code, what if I call the function again and asign the returned value to another variable:
var module_instance2 = module (args);
does that mean I now have a 2nd facade of the function or is it a new function altogether?
Cheers!
That function is the constructor of your module so each time you call that function, a new separate instance of the module is created and assigned to the receiving variable.
There is not any problem with this implementation (actually it is very common,), and you can use it wherever in your program to obtain a new instance of that module.
Best.
The module pattern is similar to namespaces in other languages, and is used to prevent global variable pollution and as a method of encapsulation.
window.module1 = (function() {} {
var version = "0.0.1";
function func1 () {};
function func2 () {};
return = {
version: version,
func1: func1,
func2: func2,
};
})()
You could have a Function DeclareModule() that defines a module on the window object.
var DeclareModule = function(name, content) {
if (typeof content === 'object') {
window[name] = content;
} else if (typeof content === 'function') {
window[name] = content();
}
};
//Declared by object
DeclareModule("module1", {
version: "0.0.1",
func1: function () {},
func2: function () {}
});
//Declared by function
DeclareModule("module1", function () {
var version = "0.0.1";
function func1 () {};
function func2 () {};
return {
version: version,
func1: func1,
func2: func2
};
});
Have a look at AMD and CommonJS modules, or an article by Addy Osmani.
Is there any reason you would ever want to call a function defined inside a namespace created using the revealing module pattern using its fully qualified name? For example, A vs. B below?
Example A.
var namespace = (function defineNamespace() {
function sayNoThankYou() { }
function callMeMaybe() {
sayNoThankYou();
}
return {
callMeMaybe: callMeMaybe,
sayNoThankYou: sayNoThankYou
};
}());
Example B.
var namespace = (function defineNamespace() {
function sayNoThankYou() { }
function callMeMaybe() {
namespace.sayNoThankYou();
}
return {
callMeMaybe: callMeMaybe,
sayNoThankYou: sayNoThankYou
};
}());
There is only one difference between namespace.sayNoThankYou(); and sayNoThankYou(); in your example: the value of this inside the sayNoThankYou function. If you don't use this inside the function, they are identical.
This is basically the framework of my code:
var firstfunction = function () {
function innerfunction () {
// Do stuff here
}
}
How do I reference innerfunction(), without changing the code mentioned supra?
If you want to expose innerFunction as an API you could do the following:
var firstFunction = function () {
var imPrivate = "foo"
var innerFunction = function () {
// do stuff
}
return {
innerFunction : innerFunction
}
}
firstFunction.innerFunction()
This would also let you create private methods, variables as well.
It seems that you're wanting to make use of currying, this is a functional programming technique where you return an function from another function i.e.:
var f1 = function() {
return function() {
}
}
> f1()();