Understanding Irakli’s code ("new" protocol)

Axel Rauschmayer axel at rauschma.de
Fri Jun 24 12:13:37 PDT 2011


I’m trying to understand all the implications of Irakli’s code.

https://gist.github.com/d33befccbe1e0ed492d5

    Object.prototype.new = function new() {
        return new this.constructor();
    };
    Object.prototype.extend = function extend(properties) {
        var constructor = new Function(), descriptor = {};
        properties = properties || {};
        Object.getOwnPropertyNames(properties).forEach(function(name) {
            descriptor[name] = Object.getOwnPropertyDescriptor(properties, name);
        });
        descriptor.constructor = { value: constructor };
        return Object.freeze(constructor.prototype = Object.create(this, descriptor));
    };

    Object.new = function new() {
        return Object.prototype.new();
    };
    Object.extend = function extend(properties) {
        return Object.prototype.extend(properties);
    };

Questions:

1. Do "new" and "extend" really work properly on any built-in other than Object?
    - E.g., I would expect String.extend() to lead to the invocation of Object.prototype.extend() which assumes "this" to be a prototype, but it is a constructor.
    - This could be fixed by checking whether "this" is a function and then acting accordingly. Or by setting up a constructor/class method "extend" for each built-in.

2. I don’t like that new() methods have to keep the result of super.new() and return it. I would prefer something like the code below, which enables a constructor behavior like in Allen’s example.

3. Are my changes really an improvement or do they impede proper interaction with built-ins, somehow?

===== Library code =====

// Optional, possibly faster: split the method below into Object.prototype.new and Function.prototype.new (the latter overriding the former)
Object.prototype.new = function new() {
    if (this instanceof Function) {
        return new this();
    } else {
        return new this.constructor();
    }
};

// Performance is less of an issue for this method
Object.prototype.extend = function extend(properties) {
    var superProto;
    if (this instanceof Function) {
        superProto = this.prototype;
    } else {
        superProto = this;
    }
    var descriptor = {};
    properties = properties || {};
    Object.getOwnPropertyNames(properties).forEach(function(name) {
        descriptor[name] = Object.getOwnPropertyDescriptor(properties, name);
    });
    var thisProto = Object.create(superProto, descriptor);
    if (thisProto.constructor) {
        thisProto.constructor.prototype = thisProto;
    }
    thisProto.__super__ = superProto;
    return thisProto;
};

// Optional: split the method below into Object.prototype.hasInstance and Function.prototype.hasInstance
Object.prototype.hasInstance = function extend(instance) {
    if (this instanceof Function) {
        return instance instanceof this;
    } else {
        return this.isPrototypeOf(instance);
    }
};

/**** Not necessary, any more (Object instanceof Object)
Object.new = function new() {
    return Object.prototype.new();
};
Object.extend = function extend(properties) {
    return Object.prototype.extend(properties);
};
****/

===== Using the library  =====

const SkinnedMesh = THREE.Mesh.extend({
    constructor: function SkinnedMesh(geometry, materials) {
        SkinnedMesh.__super__.constructor.apply(this, arguments);
        // initialize instance properties
        this.identityMatrix = THREE.Matrix4.new();
        this.bones = [];
        this.boneMatrices = [];
    },
    update: function(camera) {
        ...
        // call base version of same method
        SkinnedMesh.__super__.update.call(this);
    }
});


More information about the es-discuss mailing list