4

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

1 Answer 1

8

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();
    };
}
Sign up to request clarification or add additional context in comments.

7 Comments

Your Object.create example gives me a TypeError. According to MDC you should have something like this: var B = Object.create(C, { y: {value:'y'} });
@patrick, @TJ, yes, the properties argument should be an object that contains property descriptors, if Object.defineProperty or Object.defineProperties are not available is better to not support this argument, because you can't really mimic the property attributes in ES3. This Object.create shim has also another problem, the standard Object.create method, can accept null to create an object that doesn't inherit from anything, in this case, the new operator will replace null for Object.prototype, I also would recommend throwing in that case... See also...
@patrick, @CMS: Thanks guys, that's what I get for dashing something off and disappearing. Much appreciated.
Instead of shimming Object.create yourself, you might grab the es5-shim, which supports the second parameter, at least as much as it can under es3. github.com/kriskowal/es5-shim
@Sean: Thanks, looks interesting. The note about the second property isn't very hopeful, though: "The second argument is passed to Object.defineProperties which will probably fail silently." ;-)
|

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.