22

I just wrote some JavaScript code that follows along with what I believe to be good practice for creating an object with closure and some functions:

var myStuff = (function() {
 var number = 0;
 var fn = {};
 fn.increment = function() { number++; };
 fn.decrement = function() { number--; };
 fn.getNumber = function() { return number; };
 return fn;
})();

myStuff.increment();
myStuff.increment();
alert(myStuff.getNumber()); // alerts '2'

I have no problem writing code like the previous snippet. I would like to write some code with functionality similar to a OOP "abstract" class. Here is the result of my effort:

var myStuff = (function () {
var number = 0;
var fn = {};
fn.increment = function () { number++; };
fn.decrement = function () { number--; };
fn.doSomethingCrazy = function () { throw new Error('not implemented'); }; // I want to specify later what this does.
fn.doSomethingCrazyTwice = function () { fn.doSomethingCrazy(); fn.doSomethingCrazy(); };
fn.getNumber = function () { return number; };
return fn;
})();

myStuff.doSomethingCrazy = function () { this.increment(); this.increment(); };
myStuff.doSomethingCrazyTwice();
alert(myStuff.getNumber()); // alerts '4'

The above code snippet works, but it doesn't seem graceful. Perhaps I'm trying to force JavaScript (a functional language) to do something it isn't designed to do (object inheritance)

What is a good way to define an object in JavaScript so that a function of that object can be defined later?

Vivian River
  • 31,198
  • 62
  • 198
  • 313

5 Answers5

25

Just don't define the function.

Javascript is a duck-typed language. If it looks like a duck and it quacks like a duck, it is a duck.
You don't need to do anything special to make this work; as long as the function exists when you call it, it will work fine.

If you call it on an instance that doesn't have the function, you'll get an error at the callsite.

SLaks
  • 868,454
  • 176
  • 1,908
  • 1,964
18

I agree with SLaks, there's no need to define the function, but I tend to anyway. That's because to me the important part is in the documentation. When somebody reads my class, I want it to be clear that you must implement these methods, what arguments will be passed and what should be returned.

This is from a file at work. There were multiple implementations of a feature with a base class that did the data loading at intervals.

/**
 * Called when data is received and should update the data buffer
 * for each of the charts 
 * 
 * @abstract
 * @param {cci.ads.Wave[]} waves
 * @void
 */
updateChartsData: function(waves){
    throw "Abstract method updateChartsData not implemented";
},

2019 Update

Use TypeScript if you can Declaring abstract method in TypeScript

Ruan Mendes
  • 90,375
  • 31
  • 153
  • 217
  • Don't do this. It's an anti pattern. Make functions optional, not abstract. Or just crash and burn if someone supplies you an object without a function. – Raynos Sep 19 '11 at 21:58
  • 1
    @Raynos: Which part of it is an anti-pattern? Care to supply some reasoning? – Ruan Mendes Sep 20 '11 at 00:32
  • there is no notion of abstract in the language. It's not neccessary either. Especially an `_` internal method. This just bad design. – Raynos Sep 20 '11 at 01:35
  • 2
    @Raynos: Just because a language doesn't have the concept, it doesn't mean it's not useful. Having a base empty function may not be desirable, since it. However, what I find unacceptable is not documenting in the abstract class how the method is going to be called, which is what I don't like about `Just don't define a function`. If you choose to make all your `abstract` methods without the underscore, that's fine, our convention is to use underscore since the methods are not supposed to be called from outside the class, just be consistent. – Ruan Mendes Sep 20 '11 at 02:49
  • "outside the class" -> "outside the object". I find it bad practice to _derive_ from a "class" and call `_` methods from the "superclass". That's a different discussion though. I just generally find it bad practice to have abstract methods on a base class your inheriting from. I don't see any use cases. There are better patterns – Raynos Sep 20 '11 at 11:09
  • 1
    @Raynos: abstract methods on a base class is the standard way to implement the dependency inversion principle. http://www.oodesign.com/dependency-inversion-principle.html. My example is a use case, for different implementation of an object so the subclasses don't have to worry about the other details, they just need to know that a method will be called when needed – Ruan Mendes Sep 20 '11 at 21:14
  • @Raynos : Care to explain how else you would do this UseCase : I am supplying a Page object in Javascript which my other developers inherit/extend from (however you call it in JS). I need them to implement a initialLoad() method, otherwise a super method will fail. making inialLoad() abstract forces the developer to implement my Page object correctly. – Oliver Watkins Feb 25 '13 at 13:46
  • @OliverWatkins `var myPage = Page(function initialLoad() { ... })` – Raynos Feb 25 '13 at 15:37
7

As our team is growing and our javascript project is getting more complex we have to start implementing OO features as well.

In our javascript 'abstract' method we simply throw an error, or pop up an alert. This is an example from out Page object:

Page.initialLoad = function() { //abstract
    alert('Page.initialLoad not implemented');
};

In java world it is analagous to :

public void abstract initialLoad();

The Java code gives a compile time error, however in the Javascript we would get a runtime error. (a dirty error dialog saying that an implementing object hasn't implemented that method yet).

We have a number of disparate teams that use the Page object; the philosophy of 'duck typing' absolutely does not cut it with us. Without these pseudo 'abstract' methods we have a general lack of API communication, and sometimes we get sabotaging of the super object (ie. because a user has no idea they are supposed to implement the method).

I am tired of this 'duck typing' philosophy. I'm not sure if proponents have ever been in a complex Javascript project with 10+ developers.

Oliver Watkins
  • 12,575
  • 33
  • 119
  • 225
3

If you don't find your way graceful there is probably a way to create some functions to stramline the process to make it look better. But back to the topic...

Yes, Javascript has builtin delegation, aka inheritance, via prototypes.

Given a prototypal object:

var proto = {
    f: function(){ console.log(this.x); }
}

We can create a new object that inherits from it:

var obj = Object.create(proto);
obj.x = 42;

obj.f(); //should work!

for(var i in obj) console.log(i);
//should print x, f and some other stuff perhaps

Just note, that doing things directly via Object.create is not always supported (old browsers, etc). The old (and some may say, normal) way do do stuff is via the funky new operator (don´t think too much on the name - its confusing on purpose to distract the Java people)

function Constructor(arg){
    this.x = arg;
}

Constructor.prototype = {
    f: function(){ ... }
};

var obj = new Constructor(17);
obj.f();

An important difference to consider with prototypical inheritance is the lack of private variables. Only public variables can be inherited! Because of this, a common convention is to use underscore as a prefix for private and protected variables.

hugomg
  • 68,213
  • 24
  • 160
  • 246
  • 1
    *Everything* in JavaScript is designed to distract Java people: from the language's name all the way down to it's binary operators and 'new' keyword! :-) – Vivian River Sep 19 '11 at 21:36
  • Second parameter to Object.create should be a propertyDescriptor – Raynos Sep 19 '11 at 21:58
  • @Raynos: fixed the brain-fart; Had the old Crockford Object.create in mind, lol – hugomg Sep 19 '11 at 22:01
  • @missingno you may want to look at [pd](https://github.com/Raynos/pd) since you choose `.x = 42` instead of `{ x: { value: 42 } }` – Raynos Sep 19 '11 at 23:27
0

You might want to take a look at this previous post How do I create an abstract base class in JavaScript?

Just a few sites for some light reading for you on OOP and JavaScript, I am assuming that your new to JavaScript as an OOP langauge based of a comment you said

http://mckoss.com/jscript/object.htm

http://www.codeproject.com/KB/aspnet/JsOOP1.aspx

http://www.javascriptkit.com/javatutors/oopjs.shtml

Community
  • 1
  • 1
Spider
  • 156
  • 2
  • 8