I try to work with RequireJS and AMD module definition and have write a module that do my things in object format i think.
(i went from jquery and have not study a OOP javascript well)
myModule.js
define([
jquery,
datepicker,
], function ($, datepicker) {
var myModule = {
debug: true,
lang: 'auto',
initModule: function (element) {
myModule.element = element;
},
// ... other methods
}
return myModule;
});
And it work well, but if i try to use it for more than one elements/time it override him self, and i can't use it more than one time in same page.
main.js
requirejs(['MyModule'],
function (MyModule) {
// all the elements on page
$elements = $('.element');
$elements.each(function () {
MyModule.initModule($(this));
});
});
When i have more than one <div class="element"> on page only the last one work, i think because my module is override him self.
I tried to add new MyModule() but have a error TypeError: MyModule is not a constructor
I think i need to add a constructor or something else, in any case have a instance of my module to use instead of the object (that i think are precompiled by requirejs and returned ready for work). Any helps are good, many thanks in advance!
Ok! For do that! I completely refactor my code, and instead of return a object in my module definition i prototyped a function for get after his instance and i create a constructor for reset the properties/vars:
myModule.js
define([
jquery,
datepicker,
], function ($, datepicker) {
// constructor
var myModule = function () {
// reset lang because it maybe was changed in previous instance,
// i think because javascript share this thing trough objects?
myModule.prototype.lang = 'auto';
}
myModule.prototype.debug = true
myModule.prototype.lang = 'auto';
myModule.prototype.initModule = function (element) {
myModule.element = element;
};
// ... other methods with `myModule.prototype.` prefix
return myModule;
});
Great, now i can call myModule trough new myModuel() syntax and have same functionality for different elements on page.
main.js
requirejs(['MyModule'],
function (MyModule) {
// all the elements on page
$elements = $('.element');
var p = 1, _mod = [];
$elements.each(function () {
_mod[p] = new MyModule();
_mod[p].initModule($(this));
p++;
});
});
This work for me, i not completely understand yet what i do, but my purpose are satisfated, i can reuse same module functionality for different elemnts on page.
Suggest me readings:?
I securely need to read something about OOP Javascript, prototype and how javascript manage instance/class/object/var in memory and namespaces.
Related
I am using what I understand to be the Javascript module pattern, and jQuery.
I have an app which has a public and an admin side. Each has its own JS file, though some functionality is shared so I have extracted it to a common file. Gulp combines the common + public files into a single file for use on the public side, and the common + admin files into a single file for use on the admin side.
The public JS file includes something like:
var PublicFoo = (function () {
var bar = function() {
// ..
};
var init = function() {
$button.on('click', Common.someCommonThing);
};
return {
init: init
};
})();
The HTML page where this code is needed fires it off like so:
<script>
PublicFoo.init();
</script>
The admin JS file includes something very similar, also defining a bar() function, and calling the same Common module function.
var AdminFoo = (function () {
var bar = function() {
// ..
};
var init = function() {
$button.on('click', Common.someCommonThing);
};
return {
init: init
};
})();
The common JS file (shared and combined with both public and admin JS) includes something like:
var Common = (function () {
var someCommonThing = function() {
// Do stuff.
// When done, I want to call bar() in the calling module.
// This does not work, throws 'Uncaught ReferenceError: bar is not defined'
bar();
};
return {
someCommonThing: someCommonThing,
// ...
};
})();
From the Common module, how can I reference a function in the calling module?
I know about .caller, but apparently that is non-standard and should not be used.
I could maybe somehow pass in the name of the calling module as a parameter to Common, and reference it, but that seems ugly:
// In PublicFoo
var init = function() {
$button.on('click', function() {
Common.someCommonThing(PublicFoo)
});
};
// In Common
var someCommonThing = function(callingModule) {
// ...
callingModule.bar();
I could also of course extract the bar() call out and do it back in the calling module, but that doesn't seem so neat either:
// In PublicFoo
var init = function() {
$button.on('click', function() {
Common.someCommonThing();
bar();
});
};
// ... and the same thing in AdminFoo
I feel like this must be JS modules 101, a basic requirement, and yet I can't seem to find anything about it, though I may be searching using the wrong terminology. Or is the reason I can't find how to do this because it should not be done this way?
How can I reference the appropriate bar() from the Common module?
I know about .caller, but apparently that is non-standard and should not be used.
Also it doesn't work in your case, as the caller is the event handler and neither PublicFoo nor AdminFoo.
I could maybe somehow pass in the name of the calling module as a parameter to Common, and reference it
Yes, passing references to the thing that you want to be called is the way to go if you want someCommonThing to do different things after it has finished. Notice you really should only use such a callback when the thing is asynchronous, otherwise just returning and calling bar afterwards (like in your last snippet) is much easier.
How can I reference the appropriate bar() from the Common module?
If both bars might be loaded at once into the page, then there's no way around a parameter that references the callback.
However, that doesn't seem to be the case in your example - on one page, AdminFoo takes the role of Foo and on the other page PublicFoo takes the role of Foo.
So just reference only Foo.bar from Common! Let the respective pages fill it with the appropriate value, i.e.
var Foo = AdminFoo
on the admin page and
var Foo = PublicFoo
on the public page.
Passing functions to other functions is very common and perfectly idiomatic JavaScript, so you could do it like this:
// In PublicFoo
var bar = function() {
// ..
};
var init = function() {
$button.on('click', function() {
Common.someCommonThing(bar)
});
};
// In Common
var someCommonThing = function(bar) {
// ...
bar();
};
Is it possible to override the global require function, affecting it at process level?
From what I know, the require function is provided as argument in the function that wraps the NodeJS scripts:
(function (..., require, __dirname) { // something like this
// The wrapped code
})(...);
Is there any way to modify the require function?
(function () {
var _require = require;
require = function () {
console.log("...");
_require.apply(this, arguments);
};
})();
This will probably affect only the script where it's located.
How can we modify it at the process level?
var Module = require('module');
var originalRequire = Module.prototype.require;
Module.prototype.require = function(){
//do your thing here
return originalRequire.apply(this, arguments);
};
mock-require does this by overriding Module._load (which is what the real require actually calls).
Here is a much safer native ES6 answer based on #orourkedd which acts like an event listener on all require calls, It might look like its replacing require but if you look closer its actually saying: require = require and trap calls to it but return original behaviour. This is just one of the millions of uses of Proxy() which has been really handy for me, for example in Typescript for mapping tsconfig "paths" with the real module node will resolve.
I would go as far as to say that this is not "Monkey patching" as its on a lower level of the language.
var Module = require('module');
Module.prototype.require = new Proxy(Module.prototype.require,{
apply(target, thisArg, argumentsList){
let name = argumentsList[0];
/*do stuff to ANY module here*/
if(/MyModule/g.test(name)){
/*do stuff to MY module*/
name = "resolveAnotherName"
}
return Reflect.apply(target, thisArg, argumentsList)
}
})
This is the workaround I found. If there is any better solution, I'm open to see it.
I created a script named req-modifier.js:
module.exports = function (_args) {
var _require = _args[1];
function newRequire () {
console.log("Require is called");
return _require.apply(this, arguments);
}
newRequire.__proto__ = _require;
_args[1] = newRequire;
};
Then from the files I want to modify the require function, I do:
require("./req-modifier")(arguments);
var foo = require("./foo");
The limitation is that I have to call every time the req-modifier function.
I have a js file looking like this:
$(document).ready() {
// Mostly DOM manipulation operations
functionOne();
functionTwo();
functionThree();
...
}
What I want to achieve is to encapsulate and organize all functions in one object, and create logic so they get called only on specific pages. I started writing something like this:
(function( window, document, $, undefined) {
var MyNamespace = {};
// Cache these to local scope
MyNamespace.$window = $(window);
MyNamespace.$document = $(document);
// Functions
MyNamespace.functionOne = function() {
...
};
MyNamespace.functionTwo = function() {
...
};
})( window, window.document, window.jQuery );
I wonder if I am going in the right direction, and if there are any better ways of doing this with the page specific logic that I have not started implementing yet (I have a page identifier already available). I have looked at this book written by Addy Osmani and only thing that looked similar to what I want to achieve was the Command pattern, but I am still not convinced if it would be the right choice.
What you are looking for is kind of a class in the normal OOP sense. I personally use the following schema:
var OPTIONS = {
selectorA: '.js-xxx'
};
var MyClass = function(el) {
this.el = el;
this._init() // private function called
};
MyClass.prototype._init = function () {
// Do some stuff
};
MyClass.prototype.publicFunction = function() {
// Do exposable stuff here
}
window.instance = new MyClass(document.querySelect('#myElement'));
In order to load these modules you should need requireJS or another AMD loader.
I'm looking to encapsulate my javascript inside a namespace like this:
MySpace = {
SomeGlobal : 1,
A: function () { ... },
B: function () { ....; MySpace.A(); .... },
C: function () { MySpace.SomeGlobal = 2;.... }
}
Now imagine that instead of a few lines of code, I have about 12K lines of javascript with hundreds of functions and about 60 globals. I already know how to convert my code into a namespace but I'm wondering if there's a quicker way of doing it than going down 12K lines of code and adding MySpace. all over the place.
Please let me know if there's a faster way of doing this.
Thanks for your suggestions.
I like to wrap up the namespace like so. The flexibility is huge, and we can even separate different modules of the MySpace namespace in separate wrappers if we wanted too. You will still have to add some sort of _self. reference infront of everything, but at least this way you can change the entire name of the namespace very quickly if need be.
You can see how with this method you can even call _self.anotherFunc() from the 1st module, and you'll get to the second one.
(function (MySpace, $, undefined) {
var _self = MySpace; // create a self-reference
_self.test = function () {
alert('we got here!');
_self.anotherFunc(); // testing to see if we can get the 2nd module
};
_self = MySpace; // reassign everything just incase
}(window.MySpace = window.MySpace || {}, jQuery));
$(function () {
MySpace.test(); // call module 1
MySpace.callOtherModule(); // call module 2
});
// Here we will create a seperate Module to the MySpace namespace
(function (MySpace, $, undefined) {
var _self = MySpace; // create a self-reference
_self.callOtherModule = function () {
alert('we called the 2nd module!');
};
_self.anotherFunc = function () {
alert('We got to anotherFunc from the first module, even by using _self.anotherFunc()!');
};
_self = MySpace; // reassign everything just incase
}(window.MySpace = window.MySpace || {}, jQuery));
jsFiddle DEMO
Wrap a function body around your existing code to use as scope, hiding everything from global - this will allow you to do internal calls without pasting Namespace. prefix everywhere, neatly hide things you don't want everyone else to see, and will require minimal changes as well.
After that, decide what functions you want to "export" for everyone and assign them to properties of object you want to use as "namespace".
I want to be a javascript programmer, so I am trying to read and understand the code in chosen plugin.
I know how to create a jquery plugin, and I have read about the module pattern,
yet this code is unclear to me:
//...
attaching to jQuery object
//...
$.fn.extend({
chosen: function(options) {
return $(this).each(function(input_field) {
if (!($(this)).hasClass("chzn-done")) {
return new Chosen(this, options);
}
});
}
});
//...
//...
//...
Chosen = (function() {
__extends(Chosen, AbstractChosen);
function Chosen() {
Chosen.__super__.constructor.apply(this, arguments);
}
// ...
// attaching various events
// ...
return Chosen;
})();
If Chosen is a self invoked function - why init it using new statement?
Thanks
Chosen in the outer scope is the function/constructor returned from the inner scope that comes from the "self invoked function". That's why it's called with new.