Thursday, March 3, 2011

Can I set prototype of instantiated function?

This fails with 'X.m is not a function'...

var Y = function () {
    this.m = function () {
        alert('this is m');
    };
};

var X = new function () { };

X.prototype = new Y();
X.m();

It would certainly work if I skipped the new keyword in the X definition and then instantiated X before calling m() on it. Why can't I do it this way?

From stackoverflow
  • No you cannot set the prototype and have that change effect previously existing instances. You can however, modify the prototype object to have the desired effect. But not the way you have attempted. This is because your instance X is an object, not a class. (This is because you used the "new" operator before the definition of your class.)

    Simple test:

    var X = new function () { };
    alert(X.prototype);  // displays "undefined" because X is an 
                         // object not a class
    

    So when you set the "prototype" attribute on X you are not storing the template object in a class, you are merely creating a new attribute on object X with the name "prototype" so, if you did this:

    var Y = function () {
        this.m = function () {
            alert('this is m');
        };
    };
    
    var X = new function () { };
    X.prototype = new  Y();
    X.prototype.m();  // displays "this is m"
    

    Then you get the output you expected previously.

    Even though you created X as an instance of an anonymous class, you can still access that class through the "constructor" property. Once you have that reference, you can then modify the prototype object. Like this:

    X.constructor.prototype.m = new Y().m;
    X.m();  // displays "this is m"
    

    You should note however, that this will not work:

    X.constructor.prototype = new Y();
    X.m();  // fails
    

    Because changing the entire prototype object only effects instances created in the future.

  • You're trying to use .prototype on an object when you should be using it on a function.

    alert(typeof Y); alert(typeof X);

    You're actually creating a property on X called prototype, rather than using the "magic" protoype (try X.prototype.m() to see what I mean).

  • The prototype property should be assigned to the function you are using as a constructor before actually invoking the constructor. So this, for example, will work as you expected:

    var Y = function () {
        this.m = function () {
            alert('this is m');
        };
    };
    
    var X = function () { };
    X.prototype = new Y();
    
    new X().m();
    

0 comments:

Post a Comment