inheritance using underscore - javascript

I've been given a class -
Zoo.Controller = (function() {
function Controller() {}
Controller.prototype.params = {};
Controller.prototype.set_params = function(params) {
this.params = params;
return this;
};
return Controller;
})();
and I want to inherit from that class using _.extend
Zoo.Controllers.WhaleController = _.extend({
new: function () {
// do something
}
}, Zoo.Controller);
When I try to instantiate that class like so...
this.whale_controller = new Zoo.Controllers.WhaleController();
I get -
Uncaught TypeError: object is not a function
Is it possible to do what I'm trying? I've read multiple articles on inheritance in JS, but had assumed that the Underscore library had it solved for me.

As Bergi pointed out; it isn't hard to inherit in JavaScript. You should know what a constructor function does and what prototype is used for. This answer may help with that, I tried to demonstrate prototype through simple and hopefully easy to understand examples. You can copy and paste the code in your browsers JS commandline (in the console) and change it to see if you understand how prototype behaves in JavaScript.
To inherit from ZooController you can:
Zoo.Controllers.WhaleController = function(args){
Zoo.Controller.apply(this,arguments);//re use Zoo.Controller constructor
//and initialize instance variables
//instance specific members of Whale using an args object
this.weitht=args.weight||4;
this.wu=args.weightUnit||wu.metricTon;
//Zoo.Controller.call(this,arg1,arg2); can be used too but I usually use
// an args object so every function can pick out and mutate whatever they want
// for example: var w = new WhaleController({weight:3,weightUnit:wu.metricTon});
// now it looks more like pythons optional arguments: fn(spacing=15, object=o)
};
//set Zoo.controller.prototype to a shallow copy of WhaleController.prototype
//may have to polyfill the Object.create method if you want to support older browsers
Zoo.Controllers.WhaleController.prototype=Object.create(Zoo.Controller.prototype);
//repair constructor
Zoo.Controllers.WhaleController.prototype.constructor=Zoo.Controllers.WhaleController;
//extend Zoo.controller.prototype.set_params
Zoo.Controllers.WhaleController.prototype.set_params=function(){
//re use parent set_params
Zoo.Controller.prototype.set_params.apply(this,arguments);
//and do something extra
console.log("extra in set_params from WhaleController");
};
//WhaleController own function
Zoo.Controllers.WhaleController.prototype.whaleSpecific=function(){
//funciton specific to WhaleController
};
Polyfill for Object.create here.

I was wondering this myself, and this is what I came up with.
Define the parent
var parentObj = function(parentMemo) {
console.log(parentMemo);
};
parentObj.prototype = {
parentCall : function() {
console.log('parentCall');
}
}
Define the child
var childObj = function(childMemo, parentMemo) {
parentObj.call(this, parentMemo);
console.log(childMemo);
};
_.extend(childObj.prototype, parentObj.prototype, {
childCall : function() {
console.log('childCall');
}
});
Construct a new a child to see the results
var newChild = new childObj("Constructing Child", "Constructing Parent");
newChild.childCall();
newChild.parentCall();
Console Results:
Constructing Child
Constructing Parent
childCall
parentCall

I've read multiple articles on inheritance in JS, but had assumed that the Underscore library had it solved for me.
No, Underscore does have no helper functions for prototypical inheritance. Read the docs on what extend does:
_.extend(destination, *sources): Copy all of the properties in the source objects over to the destination object, and return the destination object. It's in-order, so the last source will override properties of the same name in previous arguments.
Most interestingly, it does not return a function, but its first argument (which is a plain object).
So get back to the articles you've read, and choose a framework that does actually have an inherit function or implement the inheritance yourself - it's not hard.

John Resig has a good blog post on implementing Javascript inheritance that may be useful to you as it contains a solution for prototype inheritance, whereas Underscore extend is designed to extend simple Javascript objects.

As others have explained, underscore's extend method creates (very) shallow copies of object instances and doesn't preserve prototype chains. However I recently came up against a small library — Compose.js — whose wider remit is to provide a more flexible API for JS's OO properties.
The second example in the readme seems to deal with your use case almost exactly — I believe in your situation it would be invoked as follows:
Zoo.Controllers.WhaleController = Compose( Zoo.Controller, { new: function () {
// do something
} );

You could reuse the extend() function used by backboneJs. Its a quite simple function that uses _.extend() too
http://backbonejs.org/docs/backbone.html#section-208
Then attach it to your Controller prototype so you could do something like:
var MyController = Controller.extend({ /* your attributes, methods */ });
hope this helps

Related

Method Added to JavaScript Object Class Appears when Traversing through Given Object

In my journey to become stronger in JavaScript, I have taken up a challenge to add a method, myMethod(), to the JavaScript Object class that can be called on a given Object, myObject, in order to manipulate its contents.
I have gotten as far as adding myMethod() to the Object prototype and traversing through myObject via myObject.myMethod(); however, I'm running into a curious problem: at the end of the given object, myMethod() is printed as an value of myObject even though, to my knowledge, it should not be.
Object.prototype.myMethod = function()
{
for (var key in this)
{
console.log(this[key]);
}
}
function processData(input)
{
//Enter your code here
var myObject = JSON.parse("{ \"myParam\": \"myValue\", \"anotherParam\": 123 }");
myObject.myMethod();
}
The following is the output of this code:
myValue
123
[Function]
Changing myObject[key] to myObject[key].toString() has the following output:
myValue
123
function ()
{
for (var key in this)
{
console.log(this[key].toString());
}
}
I am executing this script in WebStorm using a Node.js runtime.
The requirements of this challenge only calls for the contents of myObject, and I can't figure out how to stop myMethod() from showing up here. Is there something I'm missing?
In my journey to become stronger in JavaScript, I have taken up a challenge to add a method, myMethod(), to the JavaScript Object class that can be called on a given Object, myObject, in order to manipulate its contents.
Beware that this practice is seriously frowned-upon (here in 2017, possibly more than it strictly necessary*). Extending any built-in prototype is a bit fraught, but extending Object.prototype is particularly problematic since, of course, almost all objects inherit from it.
But if you're going to extend a prototype, it's important to add a non-enumerable property via Object.defineProperty or similar:
Object.defineProperty(Object.prototype, "myMethod", {
value: function() { /* ... */ }
});
The default for enumerable is false, so it won't show up in for-in loops, Object.keys arrays, etc.
* The "don't extend built-in prototypes" mantra started before ES5's introduction of a way of defining non-enumerable properties (e.g., defineProperty). Now that we can define non-enumerable properties, the chief concern is inter-script conflict, each trying to use the same name for something, or conflict with new features as they're added to JavaScript.
Use Object.defineProperty().
The Object class is used in a lot of libraries and frameworks and therefore is best left alone, but can be useful for things such as poly-fills for browser compatability.
if (!Object.prototype.myMethod) {
Object.defineProperty(Object.prototype, 'myMethod', {
value: function() { /* customer code here */ }
})
}

Extend, but for objects instead of classes

In software, we usually use the word 'extends' to refer to the subclassing of a superclass, but is there good terminology to use when 'extending' the properties of an object instead of a class in a systematic way?
for example, in JavaScript, if I have an object like so:
var foo = {
property1:'',
property2:''
}
then I have:
var bar = {
property3:''
}
if I add bar's properties to foo's properties, this is what I mean.
For whatever reason, the terminology extend has been adopted for adding the properties in one object to those in another. jQuery does this, but it probably wasn't the first. Underscore uses the same terminology:
_.extend(myObj, {newProp1: 1})
$.extend(myObj, {newProp1: 1})
Ember, on the other hand, uses extend in the subclassing sense, and the API for adding properties is Ember.merge.
The ES6 version is called assign:
Object.assign(myObj, {newProp1: 1})
There is no standard terminology and no standard way to differentiate the notions of extending an object with new properties and extending a class in the sense of subclassing it.
You may call that merging or extending. You can "extend" an object with another with a function like this :
function merge(obj1, obj2) {
for(var key in obj2) {
obj1[key] = obj2[key];
}
}
PS. Prototypal inheritance is your friend.

Understanding method chaining in javascript

I want method chaining to work, but it seems i'm not getting some concepts.
This:
$(".list").activeJS()
first has to use jQuery to get a HTMLElement nodelist and then it has to call the activeJS() function passing the nodelist.
var activeJS = function(item){
alert(item) //nodelist
}
Now i get a TypeError: $(...).activeJS is not a function error in my console.
Thx,
If you want to create a function callable from a jQuery object, you have to add it to the jQuery prototype object:
jQuery.fn.activeJS = function(item) {
// ... whatever
};
When a function is added to jQuery (which allows for chaining) it is referred to as a plugin and several things must be taken into consideration. For example, is your function itself chainable? Will your function work on a single element or multiple? I would recommend that you research jQuery plugins and build your function as a plugin in jQuery.
Here is an excellent tutorial on building a jQuery plugin that covers concepts such as chaining, passing properties and calling different plugin functions. Take a look at the article and determine if your function truly needs to be a plugin.
It may be better to simply pass jQuery and the selected elements as arguments to your function instead of chaining.
Take a look at this example:
var obj = {
fn: function(){
console.log("fn method");
return this;
},
abc: function(){
console.log("abc method");
return this;
},
oneMore: function(){
console.log("one more method");
return this;
}
};
Here chaining is provided by returning reference to obj Object.
Simply, every time you call a method on that object, you are returning that object - and you can continue calling its methods. This is basic chaining pattern that you can find in jQuery also - slightly modified but the idea is same. Thanks to dynamic nature of javascript we can do this kind of things. Chaining allows coupling of related methods that are connected by common object. This pattern has its roots in functional programming, and javascript is heavily influenced by functional languages (mostly scheme).
But too much chaining can lead to unreadable code as can be seen in lot of jQuery examples.

Extending core types without modifying prototype

How does one extend core JavaScript types (String, Date, etc.) without modifying their prototypes? For example, suppose I wanted to make a derived string class with some convenience methods:
function MyString() { }
MyString.prototype = new String();
MyString.prototype.reverse = function() {
return this.split('').reverse().join('');
};
var s = new MyString("Foobar"); // Hmm, where do we use the argument?
s.reverse();
// Chrome - TypeError: String.prototype.toString is not generic
// Firefox - TypeError: String.prototype.toString called on incompatible Object
The error seems to originate from String base methods, probably "split" in this case, since its methods are being applied to some non-string object. But if we can't apply the to non-string objects then can we really reuse them automatically?
[Edit]
Obviously my attempt is flawed in many ways but I think it demonstrates my intent. After some thinking, it seems that we can't reuse any of the String prototype object's functions without explicitly calling them on a String.
Is it possible to extend core types as such?
2 years later: mutating anything in global scope is a terrible idea
Original:
There being something "wrong" with extending native prototypes is FUD in ES5 browsers.
Object.defineProperty(String.prototype, "my_method", {
value: function _my_method() { ... },
configurable: true,
enumerable: false,
writeable: true
});
However if you have to support ES3 browsers then there are problems with people using for ... in loops on strings.
My opinion is that you can change native prototypes and should stop using any poorly written code that breaks
Update: Even this code does not fully extend the native String type (the length property does not work).
Imo it's probably not worth it to follow this approach. There are too many things to consider and you have to invest too much time to ensure that it fully works (if it does at all). #Raynos provides another interesting approach.
Nevertheless here is the idea:
It seems that you cannot call String.prototype.toString on anything else than a real string. You could override this method:
// constructor
function MyString(s) {
String.call(this, s); // call the "parent" constructor
this.s_ = s;
}
// create a new empty prototype to *not* override the original one
tmp = function(){};
tmp.prototype = String.prototype;
MyString.prototype = new tmp();
MyString.prototype.constructor = MyString;
// new method
MyString.prototype.reverse = function() {
return this.split('').reverse().join('');
};
// override
MyString.prototype.toString = function() {
return this.s_;
};
MyString.prototype.valueOf = function() {
return this.s_;
};
var s = new MyString("Foobar");
alert(s.reverse());
As you see, I also had to override valueOf to make it work.
But: I don't know whether these are the only methods you have to override and for other built-in types you might have to override other methods. A good start would be to take the ECMAScript specification and have a look at the specification of the methods.
E.g. the second step in the String.prototype.split algorithm is:
Let S be the result of calling ToString, giving it the this value as its argument.
If an object is passed to ToString, then it basically calls the toString method of this object. And that is why it works when we override toString.
Update: What does not work is s.length. So although you might be able to make the methods work, other properties seem to be more tricky.
First of all, in this code:
MyString.prototype = String.prototype;
MyString.prototype.reverse = function() {
this.split('').reverse().join('');
};
the variables MyString.prototype and String.prototype are both referencing the same object! Assigning to one is assigning to the other. When you dropped a reverse method into MyString.prototype you were also writing it to String.prototype. So try this:
MyString.prototype = String.prototype;
MyString.prototype.charAt = function () {alert("Haha");}
var s = new MyString();
s.charAt(4);
"dog".charAt(3);
The last two lines both alert because their prototypes are the same object. You really did extend String.prototype.
Now about your error. You called reverse on your MyString object. Where is this method defined? In the prototype, which is the same as String.prototype. You overwrote reverse. What is the first thing it does? It calls split on the target object. Now the thing is, in order for String.prototype.split to work it has to call String.prototype.toString. For example:
var s = new MyString();
if (s.split("")) {alert("Hi");}
This code generates an error:
TypeError: String.prototype.toString is not generic
What this means is that String.prototype.toString uses the internal representation of a string to do its thing (namely returning its internal primitive string), and cannot be applied to arbitrary target objects that share the string prototype. So when you called split, the implementation of split said "oh my target is not a string, let me call toString," but then toString said "my target is not a string and I'm not generic" so it threw the TypeError.
If you want to learn more about generics in JavaScript, you can see this MDN section on Array and String generics.
As for getting this to work without the error, see Alxandr's answer.
As for extending the exact built-in types like String and Date and so on without changing their prototypes, you really don't, without creating wrappers or delegates or subclasses. But then this won't allow the syntax like
d1.itervalTo(d2)
where d1 and d2 are instances of the built-in Date class whose prototype you did not extend. :-) JavaScript uses prototype chains for this kind of method call syntax. It just does. Excellent question though... but is this what you had in mind?
You got only one part wrong here. MyString.prototype shouldn't be String.prototype, it should be like this:
function MyString(s) { }
MyString.prototype = new String();
MyString.prototype.reverse = function() {
this.split('').reverse().join('');
};
var s = new MyString("Foobar");
s.reverse();
[Edit]
To answer your question in a better way, no it should not be possible.
If you take a look at this: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/constructor it explains that you can't change the type on bools, ints and strings, thus they cannot be "subclassed".
I think the basic answer is you probably can't. What you can do is what Sugar.js does - create an object-like object and extend from that:
http://sugarjs.com/
Sugar.js is all about native object extensions, and they do not extend Object.prototype.

Examples of practical javascript object oriented design patterns

What object oriented design patterns do you use in your application's javascript, and why?
Feel free to post code, even if there is no formal design pattern attached to it.
I have written plenty of javascript, but I have not applied much object orientated patterns to what I am doing, and I am sure i am missing a lot.
The following are three popular JavaScript patterns. These happen to be easily implementable because of closures:
The Module Pattern - Example (and made popular) by Eric Miraglia
Memoization - Example by Oliver Steele
Currying - Example by Dustin Diaz
You may also want to check out:
Pro JavaScript Design Patterns by Ross Harmes and Dustin Diaz
The following is a Google I/O talk from 2008 presented by Diaz, where he discusses some topics from his book:
Google I/O 2008 - Design Patterns in an Expressive Language
Inheritance
I use a notation for inheritance that is based on ExtJS 3, which I find works pretty close to emulating classical inheritance in Java. It basically runs as follows:
// Create an 'Animal' class by extending
// the 'Object' class with our magic method
var Animal = Object.extend(Object, {
move : function() {alert('moving...');}
});
// Create a 'Dog' class that extends 'Animal'
var Dog = Object.extend(Animal, {
bark : function() {alert('woof');}
});
// Instantiate Lassie
var lassie = new Dog();
// She can move and bark!
lassie.move();
lassie.bark();
Namespaces
I also agree with Eric Miraglia on sticking to namespaces so the code above should be run within its own context outside the window object, this is critical if you intend your code to run as one of many concurrent frameworks / libraries executing in the browser window.
This means that the only way to the window object is via your own namespace / module object:
// Create a namespace / module for your project
window.MyModule = {};
// Commence scope to prevent littering
// the window object with unwanted variables
(function() {
var Animal = window.MyModule.Animal = Object.extend(Object, {
move: function() {alert('moving...');}
});
// .. more code
})();
Interfaces
You can also make use of more advances OOP constructs such as interfaces to enhance your application design. My approach to these is to enhance the Function.prototype in order to get a notation along these lines:
var Dog = Object.extend(Animal, {
bark: function() {
alert('woof');
}
// more methods ..
}).implement(Mammal, Carnivore);
OO Patterns
As for 'Patterns' in the Java sense, I've only found use for the Singleton pattern (great for caching) and the Observer pattern for event-driven functionality such as assigning some actions when a user clicks on a button.
An example of utilising the Observer Pattern would be:
// Instantiate object
var lassie = new Animal('Lassie');
// Register listener
lassie.on('eat', function(food) {
this.food += food;
});
// Feed lassie by triggering listener
$('#feeding-button').click(function() {
var food = prompt('How many food units should we give lassie?');
lassie.trigger('eat', [food]);
alert('Lassie has already eaten ' + lassie.food + ' units');
});
And thats just a couple of tricks in my bag of OO JS, hope they are useful to you.
I recommend if you intend to go down this road that you read Douglas Crockfords Javascript: the Good Parts. Its a brilliant book for this stuff.
I am a fan of the Module Pattern. It's a way of implementing extensible, non-dependent (most of the time) frameworks.
Example:
The framework, Q, is defined like this:
var Q = {};
To add a function:
Q.test = function(){};
These two lines of code are used together to form modules. The idea behind modules is that they all extend some base framework, in this case Q, but are not reliant on each other (if designed correctly) and can be included in any order.
In a module, you first create the framework object if it does not exist (which is an example of the Singleton pattern):
if (!Q)
var Q = {};
Q.myFunction = function(){};
That way, you can have multiple modules (like the one above) in separate files, and include them in any order. Any one of them will create the framework object, and then extend it. No manual need to check if the framework exists. Then, to check if a module/function exists in custom code:
if (Q.myFunction)
Q.myFunction();
else
// Use a different approach/method
The singleton pattern is often very helpful for 'encapsulation' and organization stuff. You can even change accesibility.
var myInstance = {
method1: function () {
// ...
},
method2: function () {
// ...
}
};
cleanest way to implement a singleton in javascript
I really like jquery's method chaining pattern, allowing you to call several methods on one object. It makes it really easy to perform several operations in a single line of code.
Example:
$('#nav').click(function() {
$(this).css('color','#f00').fadeOut();
});
I really like the Decorator pattern with jQuery plugins. Rather than modifying plugins to meet your needs, write a custom plugin that just forwards requests and adds additional parameters and functionality.
For example, if you need to pass a set of default arguments around all the time, and you need slightly-different behavior that ties into business logic, write a plugin that does whatever pre and post work is necessary to suit your needs and passes your default arguments if those particular arguments aren't specified.
The main benefit of this is that you can update your libraries and not worry about porting library changes. Your code might break, but there's at least the chance that it won't.
One of useful patterns in javascript world is chaining pattern which is made popular by LINQ at first place, and also is used in jQuery.
this pattern enables us to call different methods of a class in chaining manner.
the main structure of this pattern would be as
var Calaculator = function (init) {
var result = 0;
this.add = function (x) { result += (init + x); return this; };
this.sub = function (x) { result += (init - x); return this; };
this.mul = function (x) { result += (init * x); return this; };
this.div = function (x) { result += (init / x); return this; };
this.equals = function (callback) {
callback(result);
}
return this;
};
new Calaculator(0)
.add(10)
.mul(2)
.sub(5)
.div(3)
.equals(function (result) {
console.log(result);
});
the key idea of this pattern is this key word, which makes possible accessing to other public member of Calculator fucntion.

Categories