Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Incorrect class names for constructed instances #32

Open
juntalis opened this issue Dec 18, 2014 · 0 comments
Open

Incorrect class names for constructed instances #32

juntalis opened this issue Dec 18, 2014 · 0 comments

Comments

@juntalis
Copy link

Saw the following comments, and thought I'd volunteer what I learned on the subject:

    // C is the class to be returned.
    //
    // When called, creates and initializes an instance of C, unless
    // `this` is already an instance of C, then just initializes `this`;
    // either way, returns the instance of C that was initialized.
    //
    //  TODO: the Chrome inspector shows all created objects as `C`
    //        rather than `Object`.  Setting the .name property seems to
    //        have no effect.  Is there a way to override this behavior?
    function C() {
      var self = this instanceof C ? this : new Bare;
      self.init.apply(self, arguments);
      return self;
    }

Class instance names are based on the value of Class.prototype.constructor.name. As far as I know, the name property of a function is readonly and cannot be changed after a function has been declared. In the past, I've tried a few hacky workarounds:

    /**
     * Create a new class inheriting from an old one.
     * @param {function} Class - Constructor for the old class
     * @param {string} [name] - Name of the new class.
     * @return {function}
     */
    function inheritClass(Class, name) {
        // Verify that we received a function.
        if(typeof(Class) !== 'function' || Class instanceof Function)
            throw new TypeError('Expected a function!');

        // In order to maintain the same length as the original function, we'll need to improvise.
        var emptySuper = function(){},
        fakeArgs = function(len) {
            var i = 0, params = [];
            for(; i < len; i++) {
                params.push('arg' + i);
            }
            return params.join(', ');
        },
        argsCode = Class.length === 0 ? '' : fakeArgs(Class.length),
        createSubclass = new Function('__super',
        'return function' + (name||Class.name||'') + '(' + argsCode + '){' +
            '__super.apply(this, arguments);' +
        '};'),
        subclass = createSubclass(Class);
        emptySuper.prototype = Class.prototype;
        subclass.prototype = new emptySuper();
        subclass.prototype.constructor = subclass;
        return subclass;
    };

If you do decide to do something similar, you should note the following behavior:

    function RealClass() { this.num++; }
    function FakeClass() { this.num--; }
    RealClass.prototype.num = 0;
    RealClass.prototype.constructor = FakeClass;
    var test = new RealClass();

Inspecting the test variable after running the code above should result in: FakeClass { num=1}, showing that it was RealClass being executed for the construction. Given that understanding, you should be able to set C.prototype.constructor to a generated noop function with the target name, and still have C executed without issue.

Workarounds aside, you might want to try taking a look at the approach used by
my.class. By waiting until after the user's declaration, the framework is able use the developer's own constructor function for the newly created class, which means that:

    var Car = my.Class({
        constructor: function Car() {
            if(this instanceof arguments.callee) {
                this.beep().beep().beep();
            }
        },
        beep: function() {
            console.log("beep");
            return this;
        }
    },
    car = new Car();

will work correctly, with car showing up as an instance of Car. (and the correct behavior in the constructor with regards to arguments.callee)

Anyways, lot of information for something sort of trivial, but I hope it helps.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant