23

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?

1
  • JavaScript supports object-oriented, imperative and functional programming (or rather, scripting). Commented Sep 19, 2011 at 21:29

5 Answers 5

26

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.

Sign up to request clarification or add additional context in comments.

2 Comments

As you can see, I made a point of calling my 'abstract' function from another function in the same object.
@Rice: That doesn't make a difference; that's what duck-typed means.
19

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 new Error("Abstract method updateChartsData not implemented");
},

2019 Update

Use TypeScript if you can Declaring abstract method in TypeScript

8 Comments

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: Which part of it is an anti-pattern? Care to supply some reasoning?
there is no notion of abstract in the language. It's not neccessary either. Especially an _ internal method. This just bad design.
@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.
@Raynos: abstract methods on a base class is the standard way to implement the dependency inversion principle. 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
|
9

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.

Comments

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.

4 Comments

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! :-)
Second parameter to Object.create should be a propertyDescriptor
@Raynos: fixed the brain-fart; Had the old Crockford Object.create in mind, lol
@missingno you may want to look at pd since you choose .x = 42 instead of { x: { value: 42 } }
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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.