1

I am very new to JavaScript and am coming from a C++/Java background, so I am more used to 'classical' languages.

How would I implement the following in JavaScript as it doesn't have classes!?

Suppose I have a base class A which defines some functions that derived classes B and C should implement, for example (Java ish psuedo-code):

public class A {
  public void doSomething();
  public void doSomethingElse();
};

public class B extends A {
  public void doSomething() { 
    // does B sort of something 
  };

  public void doSomethingElse() { 
    // does B sort of something else };
  };
};

public class C extends A {
  public void doSomething() { 
    // does C sort of something 
  };

  public void doSomethingElse() { 
    // does C sort of something else };
  };
};

I then want to create a B or an C and work with it, knowing that it will have the all the functions defined in A.

e.g.

A a = new B();
b.doSomething();

I don't even know if this is how I should be thinking when programming in JS? I have read some of Douglas Crockfords web pages, but I am still confused!!!.

Umbungu
  • 945
  • 3
  • 10
  • 30
  • 3
    [javascript inheritance](http://stackoverflow.com/questions/931660/javascript-inheritance) – jantimon Jun 11 '13 at 14:47
  • http://stackoverflow.com/questions/1595611/how-to-properly-create-a-custom-object-in-javascript#1598077 – Ryan Jun 11 '13 at 14:50
  • Check this out for full details and a very good example: http://stackoverflow.com/questions/387707/whats-the-best-way-to-define-a-class-in-javascript – Learner Jun 11 '13 at 14:57
  • 1
    Rq : just like C# does (by allowing single inheritance only), but even further, learning Javascipt is an opportunity to think about prefering composition other inheritance. – GameAlchemist Jun 11 '13 at 15:14
  • @jantimon (and ryan, ..ect. I've read those. – gone Jul 15 '13 at 18:00

3 Answers3

2
function A() {

};

A.prototype.doSomething = function() {
    console.log("hi")
}

A.prototype.doSomethingElse = function() {}

function B() { 
   A.apply(this,arguments) ) 
};

function C() { 
   A.apply(this,arguments) ) 
};

B.prototype = Object.create(A.prototype);
C.prototype = Object.create(A.prototype);

var b = new B();
var c = new C();

b.doSomething();
c.doSomethingElse();

You can inherit from other objects by setting those objects on the prototype chain of the function.

Since you may want to override these base functions you can then do that like this

B.prototype.doSomething = function() {
   console.log("goodbye");
}

Objects of type b will then say goodbye rather than hello when you call doSomething, c will stay the same.

Here's a fiddle you can play around with to experiment http://jsfiddle.net/Yp3UR/

There are good external resources on this in a few places

On StackOverflow you can look at

Community
  • 1
  • 1
Ben McCormick
  • 25,260
  • 12
  • 52
  • 71
1

How to think about it: In Javascript and similar languages each object has a prototype which itself is also an object. If you try to access a method or property (since functions are first class in javascript the distinction between method and property is misleading) of an object and if the interpreter can't find on the object itself it will look on the prototype. Since the prototype is also an object it also has its own prototype (the object prototype prototype). So there is this chain of prototypes, one for each level of inheritance that traces all the way up to the base class Object at which point if it still did not find the property you were trying to access the interpreter will throw an undefined property error.

How to implement it: There are numerous ways to do inheritance, this is the one I use which is not necessarely the best, but is the one easiest to understand:

//A constructor
var A= function() {};

A.prototype.doSomething= function() { };

A.prototype.doSomethingElse= function() { };

//B constructor
var B= function () {
   A.apply(this, arguments); //calls A constructor on this instance of B
};

B.prototype= new A(); //this makes B "extend" A. Basically it sets B prototype to be an instance of A.

B.prototype.doSomething= function() {
   A.doSomething.apply(this, arguments); //calling "super"
};

B.prototype.doSomethingElse= function() {
   A.doSomethingElse.apply(this, arguments); //calling "super"
};



//C constructor
var C= function () {
   A.apply(this, arguments);
};

C.prototype= new A();

C.prototype.doSomething= function() {
   A.doSomething.apply(this, arguments); //calling "super"
};

C.prototype.doSomethingElse= function() {
   A.doSomethingElse.apply(this, arguments); //calling "super"
};

So if say that C does not have the method doSomethingElse and you do something like:

c= new C();
c.doSomethingElse();

It will call A.doSomethingElse method on the c instance.

A little explanation on the .apply function: Functions in javascript "extend" Object, as such they are object themselves. In fact you can actually do this:

var myFunc= new Function("alert('myFunc');");
myFunc();

Since Functions are objects they also have their own properties and methods. "apply" is one of them.

When you say this:

//A constructor
var A= function() {};

A.prototype.doSomething= function() { };

You are actually creating a function and storing it in A, then you put a method inside A prototype (remember, functions are objects, so they have prototypes). When you do this:

var a= new A(arg1,arg2,arg3...);

You are making an instance of A, the "new" operator is a special kind of operator that basically does this:

a= A.apply(a, [arg1,arg2,arg3,...]);
a.prototype= A.prototype;

Here is an explantion of the Function.apply method: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply?redirectlocale=en-US&redirectslug=JavaScript%2FReference%2FGlobal_Objects%2FFunction%2Fapply

And here is an explanation of the "arguments" Array that is passed to it: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions_and_function_scope/arguments

When you say this:

C.prototype.doSomething= function() {
   A.doSomething.apply(this, arguments);
};

Note that A.doSomething in this case is kind of an analogue to a static function in Java, you are not calling the method of an instance of A, but actually the method present on the constructor function A (the method is actually on A.prototype, but since functions are objects the interpreter will look for it on the prototype by itself).

You can do all this because the constructor is a function and functions are objects and objects have prototypes and prototypes are objects and objects can have functions inside them. Crazy huh? But if you stop to think about the prototype chain explanained earlier it's not that hard. Just reread that sentence a couple of times.

Why all this nonsense? You are probably a little confused right now and I encourage you to look for more examples on the net. But it's easy to say that this is convoluted and overly complex, well it kind of is (in javascript) but it's also very powerful. You can modify the behavior of objects at runtime:

If you execute this little bit of code at any point in runtime

A.prototype.doSomething= function() {
    A.doSomethingElse.(apply(this, arguments));
}

you are actually modifying the behavior of all instances of A and any other class that inherits from it (all instances of B and C are also modified). In this case your A.doSomething will now behave exactly like A.doSomethingElse. Think of Java reflections without all the crazy code.

In fact you can modify the behavior of built-in classes of Javascript like String or Array: If you run this code somewhere in your program:

String.prototype.alert= function() {
   alert(this);
}

You can now do the following: "text".alert(); And a popup box will appear with "text" inside it. But don't modify built-in classes like that, it's a bad practice.

This is just one of the numerous advantages of using prototype based object orientation. There are many others.

What about private methods? They don't exist in javascript, but you can make functions that are only visible to another function through closures. If you need to make private methods I encourage you to read about closures.

Hoffmann
  • 14,369
  • 16
  • 76
  • 91
0

You need to do prototype chaining among classes. B.proto should point to A, as well as C.proto. The way to do prototype chaining is through the __proto__ attribute. In the past, there was a big controversy about __proto__ as not all JS engines implement it, although nowadays they do.

Implementation of __proto__ is still state as optional in the ES6 spec, but the standard will include a Object.setPrototypeOf() to do object chaining.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/setPrototypeOf

Here's a solution to your question, without using the new() operator. Check out this question "How to properly create a custom object in javascript" to know why the use of the new() operator to instantiate objects should be discouraged.

Object.setPrototypeOf = Object.setPrototypeOf || function (obj, proto) {
  obj.__proto__ = proto;
  return obj;
}

function A() {
    var a = {};
    a.doSomething = function() {
        console.log("A.doSomething()");
    }
    return a;
}

function B() {
    var b = {};
    Object.setPrototypeOf(b, A());
    b.doSomethingElse = function() {
        console.log("B.doSomethingElse()");
    }
    return b;
}

function C() {
    var c = {};
    Object.setPrototypeOf(c, A());
    c.doSomething = function() {
        this.__proto__.doSomething();
        console.log("C.doSomething()");
    }
    return c;
}

var a = A();
var b = B();
var c = C();

a.doSomething();
b.doSomething();
b.doSomethingElse();
c.doSomething();

Output:

A.doSomething()
A.doSomething()
B.doSomethingElse()
A.doSomething()
C.doSomething()
Community
  • 1
  • 1
Diego Pino
  • 11,278
  • 1
  • 55
  • 57
  • 1
    You're discouraging new, but encouraging \_proto\_? Do you have any particular reasons for that? The answer you cite doesn't NOT use new, it just hides it with some helper methods. `new` is a useful construct and is a part of the language for a reason. _proto_ is not part of the official ECMA spec, and there are plenty of ways to do inheritance without using it. – Ben McCormick Jun 11 '13 at 15:55
  • 1
    I think you are mixing two things, the use of new() and the use of __proto__. With regard to __proto__, as I commented in the answer, it's not standard although implemented by many JS engines. In the new standard, ES6 Harmony, there will be a standard way of doing proto chaining with setProtoypeOf(). With regard to the use of new(), I recommend reading the link I posted about "How to create an object in JavaScript". Douglas Crockford recommends not to use new() in his book "The Good Parts". There's a good reason why not to use it, but as everything, it's a matter of taste. – Diego Pino Jun 11 '13 at 16:06
  • 1
    I am afraid there are quite some issues here : a) __proto_ is non standard, which is all the more annoying that it's not useful for such simple inheritance scheme. For functions, just use F.prototype ! b) so you prefer factory other constructor functions ? no issue, but with all due respect, Crockford having had once an issue with new is not enough an argument, especially since new is XXX times faster on good JS engines. c) you are creating and storing a new function in B and C for *each* object creation, which performance/memory-wise is ... well ... and some other things... – GameAlchemist Jun 11 '13 at 16:15
  • 1
    a) I already said that in my answer b) The reason why Douglas Crockford discourages using new() is "In case you forget to use the new operator while instantiating a new object, what you get is an ordinary function call, and this is bound to the global object instead to the new object". I think is good at least to be aware of this. Now you're free to use whatever you like the most, and in fact I use new() in my code often too c) disagree, the only thing that is created is the object to be returned not a new function – Diego Pino Jun 11 '13 at 16:28
  • 1
    @DiegoPino "There's a good reason why not to use it" What is that reason exactly? I read the post and I've read "The Good Parts" both IIRC use new "under the covers" but abstract it away to use more functional notation instead. – Ben McCormick Jun 11 '13 at 16:31
  • 1
    @ben336 Functions in javascript are used for creating objects, right? Although when instantiating an object using new() it's not necessary to return *this*, some programmers prefer to do it. The reason why Crockford prefers to avoid using new() is that if a programmer forgets using it while creating a new object, then she will get a reference to the global object (bloating, most likely without noticing, the global object). Example on this fiddle: http://jsfiddle.net/dpino/xbL4Q/ – Diego Pino Jun 11 '13 at 18:29
  • 1
    sorry guys if I looked a bit dogmatic with this thing. It was not my point to say "hey, don't do this or that, because somebody says you should/should not" I think that's silly. But, I reckon there's some insight in what Crockford comments and I wanted to shared in the answer. – Diego Pino Jun 11 '13 at 18:33
  • 1
    @DiegoPino so show them how to use new correctly, or how to abstract it out, don't point them to a non-standard property thats not consistently implemented instead :) And explain your reasoning in your answer. (the question you pointed to doesn't really explain it either besides one of the answerers calling it ugly) – Ben McCormick Jun 11 '13 at 18:34