Let's say I have a javascript object...
app.dooDad = {}
(function (O) {
O.magicStuff = function() {
alert("LOL!");
}
...other methods...
})(app.doodad)
Now let's say I make a deep copy of this object...
app.specialDooDad = jQuery.extend(true, {}, app.dooDad);
(function (O) {
O.magicStuff = function() {
alert("LOL!");
alert("Cats!");
}
})(app.doodad)
I am wondering: Is there a better way to do this? That is, is there a better way to to extend the method magicStuff with additional commands in specialDooDad, without rewriting it?
thanks (in advance) for your help.
Correct me if I'm wrong, but I believe you can do something like this in Javascript:
app.specialDooDad = jQuery.extend(true, {}, app.dooDad);
(function (O) {
O.oldMagicStuff = O.magicStuff;
O.magicStuff = function() {
//Additional stuff you want to do
alert("Cats!");
O.oldMagicStuff();
}
})(app.doodad)
That only works well if you are just adding on an additional thing or two, either before or after the "original" function would run. If you need to add things into the middle, I believe you just have to rewrite the function.
I'm assuming you want to do this to maintain backward compatibility with an existing codebase (such as an open source library)?
function DooDad() {
this.magicStuff = function() {
alert("LOL!");
}
}
app.dooDad = new ConstructorA();
function SpecialDooDad() {
var o = new DooDad;
this.magicStuff = function() {
o.magicStuff.apply(this, arguments);
alert("Cats!");
}
}
app.specialDooDad = new SpecialDooDad;
I prefer this way of extending. It's more functional. You create new objects through composition and extension.
Related
I want to make use of the subscribe() function of knockout js to manually trigger an event at a certain point.
I could make an observable() and everytime put a GUID in there to trigger the scubscribe.
Is there a cleaner way within Knockout js to have a typical event-like structure?
Edit
Ok, apparently I can use observable.valueHasMutated() - might already a a bit cleaner that using a GUID.
Example
This is the behaviour that I'm looking for:
function Car()
{
var self = this;
self.onOpenDoor = ko.observable();
self.openDoor = function()
{
// using an observable / valueHasMutated for this feels a bit hacky
// is there an other way to use the underlying subscribe() system?
self.onOpenDoor.valueHasMutated();
}
}
var car = new Car();
// multiple subscribers
car.onOpenDoor.subscribe(function()
{
console.log('Do something');
})
car.o**nOpenDoor.subscribe(function()
{
console.log('Do something else');
})
car.openDoor();
I am aware this is not the default 'knockout' way to do stuff - that is not what this question is about.
Update
After #RoyJ's reference to Niemeyer's blog I went for this solution:
function Car()
{
var self = this;
self.onOpenDoor = new ko.subscribable();
self.openDoor = function()
{
self.onOpenDoor.notifySubscribers();
}
}
Update If you're just looking for clarity, you can use notifySubscribers instead of valueHasMutated. You might want to take a look at the base type of observables, ko.subscribable.
I would do it like this:
var vm = {
///...definitions...
openCount: ko.observable(0),
openDoor: function () {
vm.openCount(vm.openCount()+1);
}
};
vm.openCount.subscribe(function () {
///...do something
});
vm.openCount.subscribe(function () {
///...do something else
});
ko.applyBindings(vm);
Demo http://jsfiddle.net/uoqdfhdb/2/
Given a javascript object like this:
var myThing = {};
Object.defineProperty(myThing, 'gen', {
'get' : function() {
// access caller name here, so I can return cool/neat stuff
}
});
I want to be able to get children of myThing.gen, but know what is being asked for in the getter.
for example:
var coolThing = myThing.gen.oh.cool;
var neatThing = myThing.gen.oh.neat;
I want the "oh.cool" or "oh.neat" part in getter, so I can make decisions based on this, and return something specific to it. I am ok with solution not working in IE, or old browsers, as it is primarily for node.
The actual purpose of this is so that I can request myThing.gen.oh.neat and have the myThing.gen getter resolve to require('./oh/neat.js') and return it.
Since require cache's, this is an efficient way to dynamically load modular functionality, and have a tidy interface (rather than just dynamically building the require where needed) without having to know the structure ahead of time.
If there is no introspection-of-name function that can get this for me, I could just do something less elegant, like this:
myThing.gen = function(name){
return require('./' + name.replace('.', '/') + '.js');
}
and do this:
neatThing = myThing.gen('oh.neat');
I don't like this syntax as much, though. I looked at chai's dynamic expect(var).to.not.be.empty stuff, but couldn't figure out how to do it completely dynamically. Maybe there is not a way.
without actually solving the problem of dynamically discovering the caller, I can do this:
var myThing = {};
Object.defineProperty(myThing, 'gen', {
'get' : function() {
return {
'oh':{
'cool': require('./oh/cool.js'),
'neat': require('./oh/neat.js')
}
};
}
});
Is there a way to do this dynamically?
You can't see what the property gen will be used for in the future, so you would need to return an object with properties that react to what the object is used for when it actually happens:
var myThing = {};
Object.defineProperty(myThing, 'gen', {
'get' : function() {
var no = {};
Object.defineProperty(no, 'cool', {
get: function(){ alert('cool'); }
});
Object.defineProperty(no, 'neat', {
get: function(){ alert('neat'); }
});
return { oh: no };
}
});
Demo: http://jsfiddle.net/UjpGZ/1/
I have a few questions about Best Practises using javascript in external files and namespacing.
Let's have a namespace MyCompany, global configuration stuff, code for individual pages and maybe some "API"s.
var MyCompany = {};
Global configuration in HTML
MyCompany.root = "/";
Which approach is better
First
MyCompany.Page = {};
(function(ns} {
ns.init = function() {
var root = MyCompany.root;
ajax(root+"somepage.html");
};
}(MyCompany.Page.Home = MyCompany.Page.Home || {});
and in html use
<script>
$( function() {
MyCompany.Page.Home.init();
});
</script>
Second (Page as an Class and its instance)
MyCompany.Page.Home = function() {
var root = MyCompany.root;
this.init = function() {
ajax(root + "somepage.html");
};
};
in html
<script>
var page = new MyCompany.Page.Home();
$( function() {
page.init();
});
</script>
Submodules and Mixing API with Page javascript
If our Homepage has some reviews.
MyCompany.Page.Home.Reviews = function() {
this.init = function() {
load_stuff();
}
};
And now inside Page init use
MyCompany.Home.Page = function(data) {
var reviews = new MyCompany.Home.Page.Reviews();
this.init = function() {
reviews.init();
};
};
Could that cause troubles?
It's obvious that Reviews extends MyCompany.Home.Page, but MyCompany.Home.Page requires Reviews.
It shouldn't cause troubles if instance on MyCompany.Home.Page is created after MyCompany.Home.Page.Reviews are loaded, right? Because Reviews in fact will extend the function object, is that right?
I guess this depends on answer to first question.
It also could be
(function(ns) {
ns.init = function() { MyCompany.Page.Home.Reviews.init(); };
})(MyCompany.Page.Home = MyCompany.Page.Home || {} );
(function(ns) {
ns.init = function() { load_stuff(); };
})(MyCompany.Page.Home.Reviews = MyCompany.Page.Home.Reviews || {});
Also should I somehow separate API of Page javascript?
Such as
MyCompany.APIS.Maps = function(location) {
/* Private variables */
var _location = location;
/* Private functions */
function search_address(address) { .. do search .. }
/* Public interface */
this.search = search_address;
do some initialization ...
};
I'd be glad if anyone reads it all to leave some comment.
Thank you in advance.
Which approach is better? Revealing singleton module (first) or a constructor function/class and its instance (second)?
Depends on your use case. If you don't expect multiple page objects to exist at once (and you hardly seem to), the singleton (with an init function) is really fine. Everything else could be considered wrong or at least overkill.
Same thing holds true for your MyCompany.Page.Home.Reviews (or MyCompany.Home.Page.Reviews?) class module, of which you seem to need only one instance.
It shouldn't cause troubles if instance on MyCompany.Home.Page is created after MyCompany.Home.Page.Reviews are loaded, right? Because Reviews in fact will extend the function object, is that right?
Yes.
(function(ns) {
ns.init = function() { MyCompany.Page.Home.Reviews.init(); };
})(MyCompany.Page.Home = MyCompany.Page.Home || {} );
If you have that ns shortcut available, you should use it:
(function(ns) {
ns.init = function() { ns.Reviews.init(); };
})(MyCompany.Page.Home = MyCompany.Page.Home || {} );
Also should I somehow separate API of Page javascript?
For development: Yes, in every case. Each module should have its own file. When deploying, you might concatenate them together for faster loading, but that's a different question.
I have and external JS scripts file with all my objects in that runs once the document is ready something like this...
jQuery(function($) {
var Main = {
run: function () {
myFunction.setup();
}
}
var myFunction = {
setup: function() {
//Do some stuff here
}
}
Main.run();
});
I want to be able to run myFunction.setup() only if im on a certain page though otherwise I get errors if that method is looking for elements on the page that don't exist e.g a slideshow, menus etc.
At the moment I have got round this by checking if the element exists with .length and if it does then running the rest of the method but I was wondering if there was a nicer way? Maybe like if it was possible to send variables to the scripts file when it loads based on the page im on so it knows what to methods run?
Any help would be really appreciated.
Thanks
Giles
Paul Irish has a great way of doing exactly this, using ID and classes from the body tag to execute certain blocks of code:
http://paulirish.com/2009/markup-based-unobtrusive-comprehensive-dom-ready-execution/
This kind of thing might help:
Page specific
var page_config = {
setup_allowed: true
// ... more config
};
Generic
var Main,
myFunction;
(function ($, _config) {
myFunction = (function () {
var _public = {};
if (_config.setup_allowed === true) {
_public.setup = function () {
};
}
return _public;
})();
Main = (function () {
var _public = {};
if (typeof myFunction.setup !== "undefined") {
_public.run = function () {
myFunction.setup();
};
// Run it as we had Main.run() before
_public.run();
}
return _public;
})();
})(jQuery, page_config);
This way Main.run() and myFunction.setup() are only available if specified in page_config.
Here's a working example you can have a play with. This may be a bit verbose for your particular requirement but hopefully it'll help in some way :-)
I'm using the following format to avoid possible naming conflicts.
My main aim is to keep the parts of the program in different files during development and then later combine it
Editor is the
main.js
Editor=function(){
this.manage=function(){
}
}
var editor= new Editor;
a.js
Editor.prototype.A=function(){
this.afunct=function(){
}
}
b.js
Editor.prototype.B=function(){
var this.var1;
var this.var2;
this.bfunct=function(){
//call afunct() here
}
}
A is a set of functions that does some testing,modification etc.
afunct is a tester function which needs to be used in all the other files.
B is supposed to act as a data package and new instances of it will be created to pass around.
How will I call afunct inside bfunct?
Please help me understand how I can do this. Thank You in advance.
PS. I'm kind of a newbie in Javascript and please pardon any flaw in my logic.
It's obscure, but this might do it:
(function() {
var Editor = function() {
};
Editor.prototype = {
A: {
afunct: function() {
// Other functionality here.
}
},
B: {
bfunct: function() {
Editor.prototype.A.afunct.call(this);
}
}
};
window.Editor = Editor;
})();
var editor = new Editor();
editor.B.bfunct();
From inside B this should work
Editor.A.apply(this)
Try this from inside Editor.prototype.B:
Editor.prototype.B=function(){
var this.var1;
var this.var2;
var self = this;
this.bfunct=function(){
//call afunct() here
self.prototype.B.afunct();
}
}