3

I tried to use the following code to add a start method to an object:

var Bounce = Bounce || {
    Info : {},
    Game : {}
};

Bounce.Game.prototype.start = function() {
    Bounce.log("Starting " + new Bounce.Info());
}

But this results in the following error (on the Bounce.Game.prototype.start line):

Uncaught TypeError: Cannot set property 'start' of undefined

Looking at the object in Chrome's console, I can see that it doesn't contain the prototype object (but has toString, valueOf and constructor etc.).

This is easily fixed by adding the following line before the prototype access:

Bounce.Game = function() {};

I don't know why this is necessary when the object has already been initialized?

W3Schools tells me "Every JavaScript object has a prototype", but that doesn't appear to be the case.

11
  • 1
    Conceptually, all objects have a prototype, but only function objects have prototype property. They are not the same. If you read the ECMAScript spec, prototype is usually represented like [[Prototype]] which is an implementation detail lies in the JS engine rather than a language feature. However, in some engines [[Prototype]] can be accessed with __proto__ property. Commented Jan 2, 2015 at 11:30
  • 1
    No. Every object has a prototype. It does not, however, have a property named prototype. Two different things. Yes, this is confusing. But they are related by the fact that the function's prototype property becomes the actual prototype for new objects created using that function as a constructor. Commented Jan 2, 2015 at 11:32
  • 2
    Should really note that __proto__ is non-standard - there are better patterns. Commented Jan 2, 2015 at 11:35
  • 1
    @Leo is right, however you won't be able to call Bounce.Game.start(). check this out: jsbin.com/bapuvo/1/edit?html,js,console,output Commented Jan 2, 2015 at 11:55
  • 1
    Interesting question indeed, glad it's reopened. Commented Jan 2, 2015 at 12:36

2 Answers 2

4

Conceptually, all objects do have a prototype, but only function objects (including constructors like Object, Array, although they don't produce functions) have a property named prototype. They are not the same.

If you read the ECMAScript spec, prototype is usually represented like [[Prototype]], which is an implementation detail lies in the JS engine, rather than a language feature. However, in some engines [[Prototype]] is exposed and can be accessed with __proto__ property (non-standard).


By the way:

  1. If you want to access [[Prototype]], Object.getPrototypeOf() is your friend.

  2. When using a instanceof b, it's actually comparing a's [[Prototype]] chain with b's prototype property.

  3. And why we say null is the prototype of all? It's also not referring to prototype but [[Prototype]]:

    Object.getPrototypeOf(Object.getPrototypeOf({})) // null
    Object.getPrototypeOf(Object.getPrototypeOf(Object.getPrototypeOf([]))) // null
    Object.getPrototypeOf(Object.getPrototypeOf(Object.getPrototypeOf(new String("")))) // null
    
    // or shorter like this
    ({}).__proto__.__proto__ // null
    ([]).__proto__.__proto__.__proto__ // null
    ("").__proto__.__proto__.__proto__ // null
    
Sign up to request clarification or add additional context in comments.

1 Comment

this make me think about a workaround... I'll write an answer
2

So, inspired by @Leo comments, I think about this solution to use a plain {} object with its prototype.

We have this object:

var Bounce = Bounce || {
    Info : {},
    Game : {}
};

We define the prototype property for the given object

Object.defineProperty(Bounce.Game, 'prototype', {
    get: function() {
      return Object.getPrototypeOf(Bounce.Game); 
    }
});

Now, we can use prototype as usual:

Bounce.Game.prototype.start = function(){
  console.log('start');
};

Bounce.Game.start();

Check this out: http://jsbin.com/bapuvo/3/edit

3 Comments

Interesting approach. But why not simply Bounce.Game.start = function... ?
A prototype is meant to be "shared" across different instances, for inheritance and memory-saving reason. This solution is for the problem as @Mikaveli proposed, maybe I'll never use this approach. For instance, we don't know where this code is used and how: if it's in a full CommonJS-compliant environment, I'd rather use a proper module design solution (think about nodejs or titanium).
@Leo answering your question: yes, it's the same. As you are not gonna use new operator with a plain object, using prototype became pointless.

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.