Typescript and the __proto__ attribute
Asked Answered
G

1

8

So every mention of __proto__ is usually followed by a reference to Brendan Eich's plea not to use it. I've been playing around with some reflection in Typescript, navigating the prototype chain of a class down to a provided ancestor class using it, and would love to inject a single prototype property holding class metadata.

Does anyone have any specifics on the performance overhead I might incur, or a solution that doesn't rely on __proto__?

EDIT - Updated with code. This is just a contrived example I typed out but it illustrates what I'm hoping to do. I'm not quite sure how to benchmark the percieved slowdown caused by __proto__ mutation. But I gave it a shot anyways. Instantiation, prototype property access and method calls execute no differently given the modification.

class Base {
    public getClassName() : string {
        return this['_className'] || undefined;
    }
}

class Intermediate extends Base {   
}

class Final extends Intermediate {  
}

function traverseProtoChain(derivedClass, baseClass) {
    var cursor = derivedClass.prototype;
    while (cursor instanceof baseClass) {
        if (isDefined(cursor.constructor)) {
            var className = getProtoName(cursor);
            if (isValidString(className)) 
                cursor['_className'] = getProtoName(cursor);
        }           

        if (isDefined(cursor.__proto__)) {
            cursor = cursor.__proto__;
        }   
    }   
}
Glimp answered 26/3, 2014 at 12:30 Comment(1)
show the code which you have thoughtBale
R
20

You can use the ECMAScript 5.1 standard:

Object.getPrototypeOf(cursor)

For really quite old versions of browsers, you could attempt to fall back to __proto__ if Object.getPrototypeOf doesn't exist, but you can decide if those browsers are important given your specific context.

Here is an example that shows this. bar.prototype doesn't work, because it is an instance. getPrototypeOf works and gives you the same answer as the discouraged __proto__.

class Foo {
    constructor(name: string) {

    }
}

class Bar extends Foo {

}

var bar = new Bar('x');

console.log(bar.prototype);
console.log(Object.getPrototypeOf(bar));
console.log(bar.__proto__);

So you could write the "pleases everyone"...

if (Object.getPrototypeOf) {
    console.log(Object.getPrototypeOf(bar));
} else if (bar.__proto__) {
    console.log(bar.__proto__);
}

Final curve-ball... __proto__ is likely to become standardised in ECMAScript 6... worth bearing in mind!

Riddick answered 26/3, 2014 at 16:22 Comment(2)
Thanks for the detailed post. I was aware of of the get|setPrototypeOf, and have implemented a polyfill in my library. I was just looking for information about how it affects performance. Brendan Eich stated that given modern JS implementations, proto mutation could negatively impact on performance.Glimp
The answer is always to measure it and see if it really does.Riddick

© 2022 - 2024 — McMap. All rights reserved.