0

I'm not understanding why in the following code, obj.BaseMethod doesn't return the method defined in BaseClass constructor. In other words, why is it that

   SubClass.prototype.BaseMethod 

is defined, but

   new SubClass().prototype.BaseMethod 

is undefined.

http://jsfiddle.net/HvxJ4/4/

I'm obviously missing something important here.

function BaseClass() {
    var privatestuff = "blah";
    return {
        BaseMethod: function() {
            console.log('BaseMethod called');
        }
    }
}

function SubClass() {
    var moreprivates = "stuff";
    return {
        SubClassMethod: function() {
            console.log('SubClassMethod called');
        }
    }
}

SubClass.prototype = new BaseClass();
var obj = new SubClass();

obj.SubClassMethod(); // SubClassMethod called
obj.BaseMethod(); // Uncaught TypeError: undefined is not a function

UPDATE

I actually understood how to get my code working using

this.method = function() { } 

in my constructor function. I just didn't understand why the code above didn't do the same thing.

The answer is that if you return an object in a constructor function, you are no longer using "protoypal" inheritance.

The thing that makes this most clear to me was this answer https://stackoverflow.com/a/2118831/834770

Quoting Douglas Crockford in Chapter 5, Inheritance, of JavaScript: (...)

Douglas Crockford then explains how the new operator could be implemented as a JavaScript function. This function makes use of several other functions defined in the book, so I rewrote it in a (somewhat) simpler form below:

function createNew(constructor) {
  // a function to explain the new operator:
  //   var object = createNew(constructor);
  // is equivalent to
  //   var object = new constructor();
  //
  // param: constructor, a function
  // return: a new instance of the "constructor" kind of objects

  // step 1. create a new empty object instance
  //         linked to the prototype of provided constructor  
  var hiddenLink = function(){};
  hiddenLink.prototype = constructor.prototype;
  var instance = new hiddenLink(); // cheap trick here: using new to implement new

  // step 2. apply the constructor the new instance and get the result
  var result = constructor.apply(instance); // make this a reference to instance within constructor

  // step 3. check the result, and choose whether to return it or the created instance
  if (typeof result === 'object') {
    return object;
  } else {
    return instance;
  } 
}

So, in short, if you return an object in this function, then the inheritance bit is effectively ignored.

Community
  • 1
  • 1
user834770
  • 88
  • 7
  • As others have stated you may as well leave out the new because your function is returning an object. You can use Object.create to set prototype of any Object. Maybe the following answer will help you understand prototype and constructor/initialiser functions: http://stackoverflow.com/a/16063711/1641941 And if you're a fan of private variables you may be interested in the following answer (it uses protected instead of private because private instance specific members prevent you from using prototype): http://stackoverflow.com/a/21800194/1641941 – HMR Mar 06 '14 at 13:43

1 Answers1

1

Here's a way to think of the statement

new SubClass().prototype.BaseMethod

First, the new keyword tells JavaScript to create a new, empty object, i.e. {}

Then JavaScript sets the context (this) to be equal to that new object and calls the function after new. So in this case JavaScript will look for a function to call, but your syntax doesn't reference a defined function, so the result is undefined.

Contrast that with a typical approach for defining objects in JavaScript:

function ExampleObject() {
    // stuff related to the example object
    this.exampleProperty = "value";
}

var exObj = new ExampleOject();

In this case new creates the empty object {} as before, but now there is a defined function to call. When this function is called, the newly created object (set equal to this) will have an exampleProperty set equal to "value". The resulting object is then assigned to the variable exObj.

It may sound strange to those coming from a Java background (or similar), but JavaScript doesn't really support the concept of classes. The language made the unfortunate choice of trying to make it's prototypical inheritance look like classical inheritance, but it's really not the same. If you're going to be spending a lot of time in JavaScript, you might want to stop trying to think in terms of classes and subclasses and learn a bit about prototypes instead.

Stephen Thomas
  • 13,843
  • 2
  • 32
  • 53
  • Thanks. I thought whichever object was returned in the constructor would have its prototype set to the constructor function's prototype. But I guess this only occurs when you don't return an object? – user834770 Mar 06 '14 at 13:05
  • Here's a good [discussion](http://stackoverflow.com/questions/572897/how-does-javascript-prototype-work) of prototypes – Stephen Thomas Mar 06 '14 at 13:10