I've searched on SO and elsewhere for a simple example of inheritance and can't find one. Examples I've seen are obscure, complex, or just make me uncomfortable. I have several service functions that all share some functionality, from what I would call a baseservice:
function baseservice() {
var loadAnimate = function () {
$('#ajax-spinner').show();
};
var loadComplete = function () {
$('#ajax-spinner').hide();
};
var apiEndpoint = function() {
return "http://api.com/api/";
};
};
I have other services now that have this functionality:
var documentservice = function() {
// repeated code
var loadAnimate = function () {
$('#ajax-spinner').show();
};
var loadComplete = function () {
$('#ajax-spinner').hide();
};
var apiEndpoint = "http://api.com/api/";
var sendRequest = function (payload, callback) {
loadAnimate();
// do stuff with apiEndpoint
// call loadComplete on promise
};
How can I provide documentservice with access to those items in baseservice?
Since Javascript is a prototypical language, it doesn't have the same sort of class inheritance that a language like, say, Java has. If you want a very simple instance of inheritance, you could try something like:
function baseservice() {
this.loadAnimate = function () {
$('#ajax-spinner').show();
};
this.loadComplete = function () {
$('#ajax-spinner').hide();
};
this.apiEndpoint = function() {
return "http://api.com/api/";
};
};
var documentservice = new baseservice();
documentservice.sendRequest() = function() { /* ... */ }
Then, documentservice has all of baseservice's members (note the this. in baseservice's function declaration instead of var).
If you don't want to have to use the new keyword, you can create a function extend either adds a field pointing to baseservice (document.baseservice = baseservice) or does a deep (recursive) copy, then adds documentservice.sendRequest.
Of course, folks have already worked on this with things like ded/klass.
Related
Im doing a course in frontend Dev in uni and the teacher insists on us using a old book so to learn the history and basics of JavaScript before we move on to more advanced and recent implementations.
Now in this book we are instructed to code a webpage for a food truck and it is supposed to take orders.
Now in some scripts the objects are defined like this :
function DataStore() {
this.data = {};
}
Here the data object is defined using the keyword "this" as in saying it belongs to the function object DataStore.
however in some scripts the data object is defined as:
FormHandler.prototype.addSubmitHandler = function() {
console.log('Setting submit handler for form');
this.$formElement.on('submit', function(event){
event.preventDefault();
var data = {};
My question is what is the difference in the two data objects?
Short answer is at the bottom
Long and boring introduction to how things work
When you write this :
function SomeThing() { }
You can always do
let a = new SomeThing();
even when it doesn't make sense like in :
function lel() { console.log('lelelel'); }
let g = new lel();
console.log(g);
console.log(g.constructor.name);
What this means is that classes are actually the same as functions. And a function in which you use the keyword this usually means you will want to create instances of it.
now if I want all instances of my lel() function class to have a property called foo and a method called bar here's how you do :
lel.prototype.foo = "Some initial value";
lel.prototype.bar = function() {
console.log(this.foo);
}
now I can do
let g = new lel();
lel.bar();
lel.foo = "Hell yeah !";
lel.bar();
In conclusion, this :
function SomeThing() {
this.data = {};
}
SomeThing.prototype.setData = function(key, value) {
this.data[key] = value;
}
SomeThing.prototype.getDataKeys = function() {
return Object.keys(this.data);
}
SomeThing.prototype.getDataValues = function() {
return Object.values(this.data);
}
is the same thing as this
class SomeThing {
constructor() {
this.data = {};
}
setData(key, value) {
this.data[key] = value;
}
getDataKeys() {
return Object.keys(this.data);
}
getDataValues() {
return Object.values(this.data);
}
}
Clarifications about your question
If somewhere in your code you have :
FormHandler.prototype.addSubmitHandler = function() {
console.log('Setting submit handler for form');
this.$formElement.on('submit', function(event){
event.preventDefault();
var data = {};
if necessarily means that somewhere else in your code you have
function FormHandler(...) { ... }
Short answer
This :
function DataStore() {
this.data = {};
}
is how you define a class named DataStore with a property called data initialized to the value {}
And this :
FormHandler.prototype.addSubmitHandler = function() {
...
var data = {};
}
is how you add a method called addSubmitHandler to the already defined class FormHandler. That method uses a local variable called data, could have been any other name
In the first case, data is a property of the object that is created like this: new DataStore.
You can access this property like this:
var obj = new DataStore();
obj.data // => {}
/* or */
obj['data'] // => {}
In the second case, data is just a global variable, inside of an event handler, that is added executing the function.
var obj = new FormHandler();
obj.addSubmitHandler();
You access this variable like this:
data // => {}
I don't think it's a good idea to learn old JS. You would be out of date. You wouldn't be able to use latest technologies, and it would be harder to get a job.
I have my javascript code as follow:
$(document).ready(function () {
//call of global functions
globalFunction1();
globalFunction2(); //create a new object inside
globalFunction3();
}
function globalFunction1() {
// do something directly with jquery selectors
var testObj1 = new object1($('#tree')); // this is called later in the function
testObj.doSomething();
}
function globalFunction2() {
// do other things
}
function globalFunction3() {
// do something directly with jquery selectors
}
//creating an object in js
var object1 = (function () {
var tree;
function object1($tree) {
tree = $tree;
});
}
object1.prototype.doSomething = function () {
.....
};
return fancyStructure;
})();
Normally I have more global functions and if possible I always try to create objects using the new keyword (as in Java or C#)
Now, I am asked to provide namespacing in order to avoid function conflict problems. Thing is I am not sure how to achieve that giving my current code and knowing that I need to keep the code Object Oriented.
Hence, I am wondering if there is a way to add some namespacing effisciently. Any suggestion will do as long as it is along the lines of adding a namespace.
Just put your functions into an Object:
var mynamespace = {
globalFunction1 : function() {
// do something directly with jquery selectors
var testObj1 = new object1($('#tree')); // this is called later in the function
testObj.doSomething();
},
globalFunction2 : function() {
// do other things
},
globalFunction3 : function() {
// do something directly with jquery selectors
}
}
and call the functions with
mynamespace.globalFunction1();
Or you could just define your namespace
mynamespace = {};
And later add the the functions with
mynamespace.globalFunction1 = function() {
//do something
};
Use objects as containers for your functions. This is the standard approach of code structuring in JS.
var namespace1 = {
func1: function() {},
func2: function() {},
}
var namespace2 = {
func1: function() {},
func2: function() {},
}
namespace1.func2();
You can store your OOP code in this namespaces:
var namespace3 = {
someObj: function() {},
create: function() { return new this.someObj(); },
}
namespace3.someObj.prototype = {
count: 15,
someFunc() {}
}
And you can easily extend them:
namespace3.anotherObj = function () {}
Edit
Regarding your example:
var fancyStructureWrapped = (function () {
var tree;
function fancyStructure($tree) {
tree = $tree;
});
fancyStructure.prototype.doSomething = function () {
.....
};
return fancyStructure;
})();
// add it to some namespace
someNamespace.fancyStructure = fancyStructureWrapped;
//create an instance
var fs = new someNamespace.fancyStructure();
//and use it
fs.doSomething();
If you're looking for a general approach to managing a growing JavaScript codebase, check out RequireJS and/or Browserify. Both are libraries that allow dividing your code up into modular bits (ie. AMD or CommonJS modules) and then referencing/importing between them. They include tooling for bundling these files into a single JS file when it's time to deploy a production build too.
This is a js pattern I've found myself using and tweaking over the years.
The thing is, I fell into it after some experimentation and I'm keen to know whether this type of pattern has a name. I've browsed through a lot of design patterns but not found anything similar (or as simple, especially for modular type patterns).
var FOO = (function ($) {
var privateFuncA = function() {
...
},
privateFuncB = function() {
...
},
self = {
init: function() {
privateFuncA(); // Call a private func
self.publicFunc(); // Call a public func
},
publicFunc: function() {
...
}
};
return self;
}(jQuery));
$(function () {
// Initialise FOO
FOO.init();
});
Idea is to keep everything namespaced and allows for pseudo-public/private funcs.
If I need to go modular I'll extend the base FOO object:
// Extend FOO object
FOO.Bar = (function ($) {
var privateFunc = function() {
...
},
self = {
publicFunc: function() {
...
}
};
return self;
}(jQuery));
If you want to call publicFunc in the extended object from outside you can:
FOO.Bar.publicFunc()
Does anyone know if this type of pattern has a name or whether there's any known issues with such a design?
Sure. It's just an extension of Christian Hielmann's "Revealing Module" pattern, which was itself an extension of Douglas Crockford's Module pattern.
In a lot of my examples here on SO, I'll use something very similar, except replacing self with public_interface, to try to make it more obvious as to what is public, private or private-static.
var built_module = (function () {
var private_data = "",
private_method = function () { /* ... */ },
public_interface = {
public_method : function () { /* ... */ },
public_data
};
return public_interface;
}());
and as a constructor:
var built_constructor = (function (env_params) {
var static_data = "",
static_method = function () { /* ... */ },
public_constructor = function (params) {
var private_data = "",
private_method = function (params) { /* ... */ },
public_interface = {
public_method : function () { /* ... */ },
public_data
};
return public_interface;
};
return public_constructor;
}(envArgs));
var myInstance = built_constructor(myArgs);
The "static" data/properties are in an outer-closure, so all of the vars/functions within the inner-closure have access to them, while the "static" methods have no access to any instance-methods/data, without passing arguments into the function.
You can extend it in any way from here -- removing the return value, and instead assigning the public_interface as a property of an object, or window by default (for namespacing).
Let's say I wanted to have this API for an example to do app:
var db = new Database('db-name'); // DB connection
var todo = new Todo(db); // New "Todo" and pass it the DB ref
// I want this API:
todo.model.create('do this', function (data) {
console.log(data);
});
I have it setup currently like:
function Todo (storage) {
this.storage = storage;
};
Todo.prototype.model = {
create: function (task, callback) {
// The problem is "this" is Todo.model
// I want the "super", or Todo so I can do:
this.storage.save(task, callback);
}
}
So, if you see the comment, the problem is that "this" inside of model.create is obviously referencing Todo.model, but I need it to grab the "super".
Best I could think of was:
Todo.prototype.model = function () {
var self = this;
return {
create: function (task, callback) {
// The problem is "this" is Todo.model
// I want the "super", or Todo so I can do:
self.storage.save(task, callback);
}
}
}
But both of these aren't great. The biggest problem is that I don't want to have all my methods on model inside of a single object (1st example) or function (2nd). I want to be able to take them out from inside of the model def. Secondly, I'd like to have the todo.model.create API.
Is there a design pattern to achieve this?
You can't use the prototype pattern for todo.model as you've written it because model is a property of todo.
I think you need:
a new Model object, on which you can use the prototype model.
in the Todo constructor, create a Model object. Ideally, use a read-only "getter" function to allow that model object to be accessed, but not overwritten.
Using bind, you can do something like this:
function Todo (storage) {
this.storage = storage;
this.model = {};
var methodNames = Object.keys(TodoModel);
for(var i = 0; i < methodNames.length; ++i) {
var methodName = methodNames[i];
var method = TodoModel[methodNames];
model[methodName] = method.bind(this);
}
};
var TodoModel = {
create: function(task, callback) {
// Note that when this method is called using Todo.model.create,
// 'this' will point to the Todo instance.
this.storage.save(task, callback);
}
};
function test(storage) {
var todo = new Todo(storage);
var task = {};
todo.model.create(task, function(err, savedTask) {
// ...
});
}
The TodoModel is basically a map, so you can replace it with a Map collection and you will no longer need to call Object.keys.
You could set up the model in the constructor like in the following example:
function Todo (storage) {
var self = this;
this.storage = storage;
this.model = {
create: function(task, callback) {
self.storage.save(task, callback);
}
};
};
Alternatively, you could use bind, but I think that it would unnecessarily complicate things, because you must find an implementation that works on older browsers and it does not conflict with the native implementation in newer browsers that support EcmaScript 5.
Ok this may be a noobolicious question as im new to OOP.
Im attempting to build something of a JS Object Library and was wondering if I could do it using nested functions??
var object = new function() {
this.action1 = function () {
this.dostuff1 = function () {
return "dostuff1";
};
this.dostuff2 = function () {
return "dostuff2";
};
};
I am having trouble accessing the third level functions. Can I nest like this?
this.action2 = function () {
return "action2";
};
alert(object.action1.dostuff2());
While Eberlin's answer is perfectly correct I'd suggest you to create a nested object which in turn again exposes functions rather than nesting functions itself. Otherwise this might become a maintainability nightmare.
Basically you could create
var Child = function(){
//constructor
};
Child.prototype.doStuff2 = function(){
return "dostuff2";
};
var Root = function(obj){
//constructor
this.child = obj;
};
Root.prototype.action1 = function(){
return "doStuff1";
};
//usage
var myRoot = new Root(new Child());
myRoot.action1();
myRoot.child.action2();
Here's a live example: http://jsbin.com/ijotup/edit#javascript,live
See below for some code cleanup:
var o = (new function () { // changed 'object' to 'o'
this.action1 = (function () { // added parentheses, not required.
this.dostuff1 = (function () { // does not return anything.
return "dostuff1"; // and is also not the proper way to organize
}); // ** look at the javascript prototype
return this; // now it does
}); // missing closing bracket
this.dostuff2 = (function () {
return "dostuff2";
});
});
alert(o.action1().dostuff2()); // action1 is a function, not a variable.
Hope this helps. Also, here's a brief tutorial on the javascript prototype.