Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Trouble with prototype chain in JavaScript

Tags:

javascript

Why can't I access the 'x' property from A?

A = {}; B = {y: 'y'}; C = {x: 'x'}; A.prototype = B; B.prototype = C; A.x
like image 688
Vanson Samuel Avatar asked Feb 26 '23 22:02

Vanson Samuel


1 Answers

The prototype of an object is not reflected by the prototype property (confusing though that may be). In fact, there is no standard, direct way of setting the prototype of an object after you've created it (and it's only very recently that there's been any standard way to retrieve an object's prototype). In the code you've quoted, all you've done is create a normal property called prototype on the objects; it may as well have been called foo. :-)

There is a special prototype property in JavaScript, but it's on functions: It's the object that will be assigned as the prototype of the objects created by that function if you use it with the new keyword (e.g., as a constructor function). In fact, until very recently the only way to assign a prototype to an object was through a constructor function:

function makeA() {
}
makeA.prototype.x = "foo";

A = new makeA();
alert(A.x); // alerts "foo"

...and that's still the only widely-supported means of doing it.

Things are changing slightly with the new ECMAScript 5th edition specification, but you can still only set the prototype of an object when you create it, not after the fact. What the new stuff does is make it possible to do it directly rather than by making a constructor function to do it. This is the new Object.create feature in Section 15.2.3.5, but it's not widely supported yet. (There are several other nifty features of the 5th edition, including the ability to get the prototype of an object via Object.getPrototypeOf; but still no way to change it after the fact.)

There is a non-standard property that some implementations (like Firefox's SpiderMonkey engine) provide, __proto__, but it's not supported broadly and was not included in the latest specification.

Using the new Object.create, you could do what you want like this:

var C = {x: 'x'};
var B = Object.create(C);
B.y = 'y';
var A = Object.create(B);
alert(A.x); // alerts "x"

...but since Object.create is so new, you'll find that in most implementations, you need to create it because it's not there. That's easy enough if we ignore its second argument (which can only be partially emulated):

if (!Object.create) {
    // An *incomplete* emulation of Object.create, doesn't support the optional
    // second parameter defined by the spec.
    Object.create = function(proto) {
        var obj;

        // There's no point in calling this with a null or otherwise "falsy"
        // prototype, but let's handle it if you do
        if (!proto) {
            return {}; // Just a generic object
        }

        // Define a constructor object that uses
        // the prototype
        function ctor() {
        }
        ctor.prototype = proto;

        // Create and return the object
        return new ctor();
    };
}
like image 113
T.J. Crowder Avatar answered Mar 07 '23 10:03

T.J. Crowder