JavaScript inheritance without the 'new' keyword - javascript

I'm used to using this pattern all over my code, and I like it:
var UserWidget = (function(){
var url = "/users",
tmpl = "#users li", $tmpl;
function load() {
$tmpl = $(tmpl);
$.getJSON(url, function(json){
$.each(json, function(i, v) {
appendUser(v);
});
});
}
...
return {
load: load
};
})();
However, I have many "widget" objects. "ProfileWidget", "PlayerWidget" etc etc. and there's certain actions that each widget share. So ideally, if we're thinking object-orientally, I want each widget object to inherit some methods from a main "Widget" class.
How can I do this without changing this lovely pattern I've been using?
To be more clear I'd like to be able to do something like this:
var Widget = (function() {
function init() {
console.log("wow yeah");
}
})();
// have UserWidget inherit somehow the Widget stuff
var UserWidget = (function() { ...
UserWidget.init(); // -> "wow yeah"

Keep in mind these solutions are not what I'd typically reccomend and they are just to satisfy the question.
What about closing over everything so that its accessible from your "sub classes" (demo)
var Widget = (function () {
var init = function () {
console.log("wow yeah");
};
var User = (function () {
var load = function () {
init();
};
return {
'load': load
};
} ());
return { 'User': User };
} ());
// Usage: This loads a user and calls init on the "base"
Widget.User.load();
Another way (demo) that you might like is to just use proper inheritance, but within the closure and then return one and only one instance of that new function. This way lets you keep User and whatever else an object
// Closing around widget is completely unneccesarry, but
// done here in case you want closures and in case you
// dont want another instance of widget
var Widget = (function () {
// definition that we'll end up assigning to Widget
function widget() {
console.log("base ctor");
}
// sample method
widget.prototype.init = function () {
console.log("wow yeah");
};
// put widget in Widget
return widget;
} ());
var User = (function () {
function user() { }
user.prototype = new Widget();
// TODO: put your User methods into user.prototype
return new user();
} ());
var Player = (function () {
function player() { }
player.prototype = new Widget();
// TODO: put your Player methods into player.prototype
return new player();
} ());
User.init();
Player.init();

I decided to use Crockford's object:
// function from Douglas Crockford, comments from me
function object(o) {
// define a new function
function F() {}
// set the prototype to be the object we want to inherit
F.prototype = o;
// return a new instance of that function, copying the prototype and allowing us to change it without worrying about modifying the initial object
return new F();
}
// Usage:
var Widget = (function() {
function init() {
console.log("wow yeah");
}
return {
init: init
};
})();
var UserWidget = (function() {
var self = object(Widget); // inherit Widget
function priv() {}
self.pub = "boom";
...
return self;
})();
UserWidget.init() // -> "wow yeah"
This works great for me and I like it!

You could use Object.create(obj), which I believe is what you're looking for.

Without using new, you'll have to use the __proto__ property rather than prototype, so this won't work in all browsers.
var Widget = {
init: function () {
console.log("wow yeah");
}
};
var UserWidget = (function(){
var url = "/users",
tmpl = "#users li",
$tmpl;
function load() {
$tmpl = $(tmpl);
$.getJSON(url, function(json){
$.each(json, function(i, v) {
appendUser(v);
});
});
}
return {
load: load
};
})();
UserWidget.__proto__ = Widget;
UserWidget.init();
Demo: http://jsfiddle.net/mattball/4Xfng/

Here's a simple example of prototyping in JS... For more detail on this topic read "JavaScript: The Good Parts"
// widget definition
var Widget = {
init: function () {
alert('wow yeah!');
}
};
// user widget definition
var UserWidget = function () { };
UserWidget.prototype = Widget;
UserWidget.prototype.load = function () { alert('your code goes here'); }
// user widget instance
var uw = new UserWidget();
uw.init(); // wow yeah!
uw.load(); // your code goes here
Hope this helps!

Related

JavaScript "Class" Structure to avoid using x = new widget();

I would like use the following syntax where the parameter is an ID of HTML element, very similar as to how you setup JWPlayer but I can't figure out how they did it. This is so I can make it as simple as possible for someone else to use.
myWidget("htmlTargetId");
I'm trying to avoid having to do:
myWidget = new MyWidget("htmlTargetId");
I know that I can create the first by doing:
var myWidget = function(target) {
// Do something here
}
myWidget("htmlTargetId");
I need to add methods and properties etc but I would like a "constructor" that will create elements in the "htmlTargetId". What would be the best way to do this?
I tried a few variations, this is the latest attempt:
var myWidget = (function () {
var _target = undefined;
// constructor
var widget = function (target) {
_target = target;
version = 12;
};
widget.prototype = {
constructor: widget,
doSomething: function () {
console.log("I will so something to", target);
}
};
return widget;
})();
// Try out the new code
myWidget("htmlTargetId");
console.log(myWidget.version);
myWidget.doSomething();
But this gives me "undefined" and "Uncaught TypeError: undefined is not a function" I assume this is because the return statement is returning a function rather than an object because I'm not using "new"?
// Trying to avoid having to do this
superWidget = new myWidget("htmlTargetId");
Many thanks!
If you want to have multiple Widget instances,
var myWidget = (function () {
// constructor
var Widget = function (target) {
this._target = target;
};
Widget.prototype = {
constructor: Widget,
version: 12,
doSomething: function () {
console.log("...", this._target);
}
};
return function init(target) {
return new Widget(target);
};
})();
var widget1 = myWidget("foo"),
widget2 = myWidget("bar");
console.log(widget1.version); // 12
widget1.doSomething(); // "..." "foo"
widget2.doSomething(); // "..." "bar"
However, if you only need one "instance", you don't need any constructor:
var myWidget = function (target) {
myWidget._target = target;
};
myWidget.version = 12;
myWidget.doSomething = function () {
console.log("...", myWidget._target);
}
myWidget("foo");
console.log(myWidget.version); // 12
myWidget.doSomething(); // "..." "foo"

How to eliminate code repetition between different View Model modules?

My JS is organized into viewmodels and services. The services are mostly concerned with AJAX calls, whereas my viewModels describe the view that they're used in.
I have two view models now - StoreViewModel, and MyStoreViewModel. In each of these, I have the following:
function MyStoreVm(model) {
var self = this;
self.doThis = function(){
// do stuff
self.doThat();
};
}
Then:
function StoreVm(model) {
var self = this;
self.doThis = function(){
// do stuff
self.doThat();
};
}
I come from a C# background - normally I would just use inheritance in this kind of situation. How can I eliminate this code repetition between two distinct modules / viewmodels, by having them inherit from a third, shared module?
More details: These are being used in an MVC view where I have knockout bindings depending on whether or not the store is MyStore:
#if (!Model.IsMyStore) {
<script type="text/javascript">
$(document).ready(ko.applyBindings(new StoreVm(#Html.Raw(JsonConvert.SerializeObject(Model, new JsonSerializerSettings() { ContractResolver = new CamelCasePropertyNamesContractResolver() })))));
</script>
} else if (Model.IsMyStore) {
<script type="text/javascript">
$(document).ready(ko.applyBindings(new MyStoreVm(#Html.Raw(JsonConvert.SerializeObject(Model, new JsonSerializerSettings() { ContractResolver = new CamelCasePropertyNamesContractResolver() }).Sanitize()))));
</script>
}
UPDATE
I looked into some of the suggestions below, but none seemed clean and simple enough for my novice skills. I tried the following which seems to work:
function BaseStore(model){
self.doThis = function(){
// do stuff
self.doThat();
};
// and a whole lot of other shared code
}
function StoreVm(model) {
var storeVm = new BaseStoreVm(model)
var self = storeVm;
self.isolatedFunctionForGenericStores = function(){stuff}
// other stuff for only this type
return storeVm;
}
function MyStoreVm(model) {
var myStoreVm = new BaseStoreVm(model)
var self = myStoreVm;
self.isolatedFunctionForMyStore = function(){stuff}
// other stuff for only this type
return myStoreVm;
}
Is there anything wrong with this approach?
If you have two child types that need to inherit from the same parent, you can do:
function Parent( foo ) {
this.foo = foo;
}
Parent.prototype.method = function() {
console.log( this.foo );
};
function Child1() {
Parent.call( this, "bar" );
}
Child1.prototype = Object.create( Parent.prototype );
Child1.prototype.constructor = Child1;
function Child2() {
Parent.call( this, "qux" );
}
Child2.prototype = Object.create( Parent.prototype );
Child2.prototype.constructor = Child2;
var parent = new Parent("blah");
var child1 = new Child1();
var child2 = new Child2();
parent.method(); // => "blah"
child1.method(); // => "bar"
child2.method(); // => "qux"
First you should understand how JavaScript implement inheritance. JavaScript is a prototype-based language which contains no class statement, such as is found in C#. Instead, it uses functions as classes(no classes, just objects).
So what we have here is objects inherit from other objects (now you might need to get some coffee).
So then JavaScript does not give you the full power of inheritance and polymorphism you get in C#.
If you want to know ways to implement inheritance in JS:
SO: Performing inheritance in JavaScript
My Blog: Javascript Inheritance techniques
Back to your question, i think you may need to implement The Factory Pattern. So your js code could be like that:
function MyStoreVm(model) {
var self = this;
self.doThis = function() {
// do stuff
self.doThat();
};
}
function StoreVm(model) {
var self = this;
self.doThis = function() {
// do stuff
self.doThat();
};
}
// Define factory object that create your proper store object
// StoreFactory takes the model as input.
// You can change it to accept seconf parameter that define class type
function StoreFactory() {
this.classType == "MyStoreVm"; // default value
this.createStore = function(model) {
if (model.IsMyStore === true)
this.classType = MyStoreVm;
else
this.classType = StoreVm;
return new this.classType(model);
}
}
Then in your MVC view:
$(document).ready(function() {
var mystoreFactory = new StoreFactory();
ko.applyBindings(mystoreFactory.createStore((#Html.Raw(JsonConvert.SerializeObject(Model, new JsonSerializerSettings() {
ContractResolver = new CamelCasePropertyNamesContractResolver()
})))));
});
Check out Klass.js. While this is basically the same as creating your own prototypes and inheritance methods, it's nice to use. It's also AMD aware.
// base class
var Store = klass(function() {
var self = this;
// add properties here
}).methods({
doThis: function () {
// do this
},
doThat: function () {
// do that
}
});
return Store;
// create the first constructor
var myStoreVm = Store.extend(function () {
// super class is called
}).methods({
doThis: function(){
this.supr(); // call Store.doThis
// some other code
}
});
return myStoreVm;
// create the second constructor
var storeVm = Store.extend(function () {
// super class is called
}).methods({
doThis: function(){
// override Store.doThis with my own code
}
});
return storeVm;

Simple JavaScript OOP Class

I'm using John Resig's simple OOP Class that is adapted to use "use strict" and taken from SO post.
In all examples I see the usage of Class.extend like so:
var MyObj = Class.extend({
init:function(){},
prop: "Property"
});
But I found a large disadvantage for me of using it in such way - I cannot have "private" variables, so I cannot store reference to this like var $this = this;.
I found the solution for my case, and now I using the Class.extend in following way:
var MyObj = Class.extend(new function(){
var $this = this;
this.init = function(){};
this.prop = "Property";
});
Everything works in my case, but I want to know if there some things that can cause me problems in a long run?
Does this way my application will consume much more memory in browser?
What alternative ways I have to implement my needs?
Note: I need to store $this, because I use heavily events and callbacks, so I want to refer "original" this easy to have access to all methods and properties on object.
EDIT: As requested, this is my code example:
(function () {
"use strict";
window.QuickPlay = Class.extend(new function () {
var $this = this;
this.init = function (initData) {
$this.elementsToHide.push(initData.el);
$(function () {
playProcessStart();
Sys.Application.add_load(function () {
$find("ctl00_ContentPlaceHolderMain_ctrlPlayPopup1").add_closed(function () { $this.setElementsVisibility(""); });
});
$this.setElementsVisibility("hidden");
});
};
this.elementsToHide = [];
this.setElementsVisibility = function (visibility) {
$.each($this.elementsToHide, function (i) {
$("#" + this).css("visibility", visibility);
});
};
});
} ());
You can use module pattern and maintain all the OOP. These kind of pattern gives your code more security and better organization.
//these are namespaces in javascript
window.project = window.project || {}; //this kind declarations prevents recreate the object
project.group = project.group || {};
//in the line below we can use $ instead jQuery, and use window and document instead ask for the browser every time.
(function (window, document, $) {
"use strict";
project.group.NameOfYourModule = function () {
var privateAttribute = true,
students = 32, //It's is a best practice declare everything in an unique var.
privateMethod = function () {
alert('Now I know OOP using jQuery');
};
return {
init: function () {
//this is a public method and we can initiate some private method;
privateMethod();
//we call a public method using this
this.publicMethod();
},
publicMethod: function () {
//this is a public method
}
};
};
$(function () {
var myclass = new project.group.NameOfYourModule(); //instantiate you class
myclass.init(); //initiate some public method
});
}(window, document, jQuery));
Working example at JsFiddle
How to work with Inheritance and Module Pattern here
I cannot have "private" variables
Of course you can. Either in the (currently unnecessary) (function () { … } ()); wrapper, or in your constructor (the init thing).
new function () {
Avoid that pattern! If you really need your code to work as it does now, use
(function () {
"use strict";
// Here's the place where you could put a private, static variable
// for example `var elementsToHide = [];`
var $this = {
init: function (initData) {
$this.elementsToHide.push(initData.el);
$(function () {
playProcessStart();
Sys.Application.add_load(function () {
$find("ctl00_ContentPlaceHolderMain_ctrlPlayPopup1").add_closed(function () {
$this.setElementsVisibility("");
});
});
$this.setElementsVisibility("hidden");
});
},
elementsToHide: [],
setElementsVisibility: function (visibility) {
$.each($this.elementsToHide, function (i) {
$("#" + this).css("visibility", visibility);
});
}
};
window.QuickPlay = Class.extend($this);
}());
I want to know if there are some things that can cause me problems
Yes. Multiple instances will hardly work, as they all do reference the same elementsToHide array. And you're not using any instance methods at (only a constructor and static elements on your class), so the class pattern seems quite unnecessary. Use a module instead. If you need single instances (and classes), the code should look like this:
"use strict";
window.QuickPlay = Class.extend({
init: function (initData) {
var $this = this;
this.elementsToHide = [];
$(function () {
playProcessStart();
$this.elementsToHide.push(document.getElementById(initData.el));
Sys.Application.add_load(function () {
$find("ctl00_ContentPlaceHolderMain_ctrlPlayPopup1").add_closed(function () {
$this.setElementsVisibility("");
});
});
$this.setElementsVisibility("hidden");
});
},
setElementsVisibility: function (visibility) {
$(this.elementsToHide).css("visibility", visibility);
}
});

JS turning a function into an object without using "return" in the function expression

i have seen in a framework (came across it once, and never again) where the developer defines a module like this:
core.module.define('module_name',function(){
//module tasks up here
this.init = function(){
//stuff done when module is initialized
}
});
since i never saw the framework again, i tried to build my own version of it and copying most of it's aspects - especially how the code looked like. i tried to do it, but i can't seem to call the module's init() because the callback is still a function and not an object. that's why i added return this
//my version
mycore.module.define('module_name',function(){
//module tasks up here
this.init = function(){
//stuff done when module is initialized
}
//i don't remember seeing this:
return this;
});
in mycore, i call the module this way (with the return this in the module definition):
var moduleDefinition = modules[moduleName].definition; //the callback
var module = moduleDefinition();
module.init();
how do i turn the callback function into an object but preserve the way it is defined (without the return this in the definition of the callback)?
you have to use:
var module = new moduleDefinition();
and then you're going to get an object.
Oh, and maybe you want to declare init as this:
this.init = function() {
Cheers.
How about something like this (I can only assume what mycore looks like):
mycore = {
module: {
definitions: {},
define: function(name, Module) {
this.definitions[name] = new Module();
this.definitions[name].init();
}
}
};
mycore.module.define('module_name', function () {
// module tasks up here
this.init = function () {
// init tasks here
console.log('init has been called');
};
});
I don't know what framework you're using or what requirements it places on you, but Javascript alone doesn't require a function to return anything, even a function that defines an object. For example:
function car(color) {
this.myColor = color;
this.getColor = function() {
return this.myColor;
}
//note: no return from this function
}
var redCar = new car('red');
var blueCar = new car('blue');
alert(redCar.getColor()); //alerts "red"
alert(blueCar.getColor()); //alerts "blue"
One more alternative http://jsfiddle.net/pWryb/
function module(core){this.core = core;}
function Core(){
this.module = new module(this);
}
Core.prototype.modules = {};
module.prototype.define = function(name, func){
this.core.modules[name] = new func();
this.core.modules[name].name = name;
this.core.modules[name].init();
// or
return this.core.modules[name];
}
var myCore = new Core();
var myModule = myCore.module.define('messageMaker', function(){
this.init = function(){
console.log("initializing " + this.name);
}
})
myModule.init();

javascript design pattern: how to create sub-module and access parent module private vars and functions

I have the following:
mod.a = (function() {
var myPrivateVar = 'a';
function myPrivateFct() {
//do something I will need in my sub-module (mod.a.b)
}
return {
//some public functions
}
})();
mod.a.b = (function() {
// some local vars and functions
return {
mySubModuleFct:function() {
// here I want to call mod.a.myPrivateFct();
}
})();
I want to create a sub-module and call a private function from my parent module mod.a. How can I do this while following the best practices of the module pattern?
A coworker showed me how to do it. It's actually very elegant.
mod.a = (function() {
var myPrivateVar = 'a';
function myPrivateFct() {
//do something I will need in my sub-module (mod.a.b)
}
return {
b: {
bPublicMethod:function() {
myPrivateFct(); // this will work!
}
}
//some public functions
}
})();
//call like this
mod.a.b.bPublicMethod(); // will call a.myPrivateFct();
I would suggest using John Resig's Simple Inheritance code for more object-oriented approach to javascript:
http://ejohn.org/blog/simple-javascript-inheritance/
It allows you to write this:
var Person = Class.extend({
init: function(isDancing){
this.dancing = isDancing;
}
});
var Ninja = Person.extend({
init: function(){
this._super( false );
}
});
var p = new Person(true);
p.dancing; // => true
var n = new Ninja();
n.dancing; // => false

Categories

Resources