3

I want to add a method to the prototype of an inner class. Is that possible?

This is what I tried:

var Foo = function Foo() {};
Foo.prototype = {

    Bar: function Bar() { },
    Bar.prototype: { // <- this does not work

        barMethod: function () {
            console.log('hello');
        }

    },

    fooMethod: function () {
        var bar = new this.Bar();
        bar.barMethod();
    }

}

var foo = new Foo();
foo.fooMethod();

But Bar.prototype doesn't work, it throws a SyntaxError with the message Unexpected token ..

4
  • Why do you use "inner classes"? And why do you store them on the prototype? Commented Jun 20, 2015 at 14:21
  • 5
    You will need to follow the normal rules for object literals. You cannot have "nested property names". Use an assignment instead. Commented Jun 20, 2015 at 14:22
  • 1
    Minor nit, JS doesn't have classes. On one level ES6 does, but it's syntactic sugar. Commented Jun 20, 2015 at 14:54
  • Alright. :) I should have said something like "I want to add a method to a nested prototype" or something like that. Commented Jun 20, 2015 at 15:13

2 Answers 2

3

Your problem is that you're defining the Foo.prototype object, and as such, you're bound to the rules and syntax of object creation, for example the parser expects you to list the attributes in a key: value, nextkey: nextvalue format, which Bar.prototype does not fit. (Keys are effectively strings, and it doesn't make sense to use . in them, as they would create ambiguity while parsing*)

Try this:

var Foo = function Foo() {};
Foo.prototype.Bar = function Bar() { };
Foo.prototype.Bar.prototype = {

    barMethod: function () {
        console.log('hello');
    }

};

There's a slight semantic difference though, as this way you're not overriding the prototype, just extending it. (consider equaling it to {} first, then extending it with every attribute of the object you tried to create)


(*) A note on ambiguity: I mention above that having a . in your object key would create ambiguity, here's a simple example:

var foo = {
   bar: {
       baz: 0,
       qux: 20
   },
   bar.baz: 150 //note that this will throw an error
};
console.log(foo.bar.baz);

If this code above wouldn't throw an error, what would you expect console.log(foo.bar.baz) to print, 0 or 150?

That's why it doesn't make sense to use . in a key, and that's why the parser throws the unexpected token error on any ..

Of course, you could use the "bar.baz" string as a key as "bar.baz": 150 above (please don't!), but then you'd have to reference the value as

foo["bar.baz"]

which would be distinctly different from

foo.bar.baz;

All in all, this is just some intuition-based reasoning behind why you can't use a . in your keys, but the real reason is plainly this: because the parser will throw an error.

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

8 Comments

Appear to return TypeError: Cannot set property 'prototype' of undefined ?
Well first you have to create Foo (the way you originally did), of course, I omitted that line.
Alright, this works the way I want. But where exactly is the semantic difference? Where would you add = {};?
You dont need to add it in this case. I was just pointing out that if you're doing f.prototype= {...} then you're redefinind the prototype attribute, while f.prototype.bar = ... is just adding bar to whatever the prototype attribute was before.
I understand that Bar.prototype: is simply not supported. But why would a . in a string create ambiguity while parsing?
|
1

In an object literal you can only define properties of that object literal, but not properties of the values.

However, if you want to set the prototype when creating the object, consider Object.assign (which can be polyfilled):

Foo.prototype = {
  Bar: Object.assign(function Bar() { }, {
    prototype: {
      barMethod: function () {
        console.log('hello');
      }
    }
  }),
  fooMethod: function () {
    var bar = new this.Bar();
    bar.barMethod();
  }
};

However, note that replacing all the prototype is a bad practice because you erase the constructor property.

3 Comments

I should have mentioned I use node.js (v0.12.4), which doesn't have Object.assign available. There is a shim available (npmjs.com/package/object.assign), but I haven't tested it.
Oriol, in this case, he was trying to replace the prototype property of a function (not to be confused with the prototype of the function that getPrototypeOf would return) with a new object, meaning that new objects created with this function would still have the constructor property, as their prototype would be Object.
@doldt Yes. In my answer I only talked about prototype, not [[Prototype]].

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.