1

I am trying to combine an existing object with a class that extends it (and its prototype).

The code is below, I can of course add more detail if needed but I think this covers the problem. As specified amongst the code, the error is TypeError: this.prototype is undefined. The last line in this snippet is the call which causes this error, the error itself occurs in the .addMixin(mixin) function.

The references I have used to get here include: http://www.joezimjs.com/javascript/javascript-mixins-functional-inheritance/ and http://javascript.crockford.com/prototypal.html (though this was a stepping stone to reach above)

Note: I know this can be done with JQuery and other libraries but I want to do this Vanilla.

// setup some tools
var config = {
  writable: true,
  enumerable: true,
  configurable: true
};

var defineProperty = function(obj, name, value) {
  config.value = value;
  Object.defineProperty(obj, name, config);
}

// And mixins
Object.prototype.addMixin = function (mixin) {    
    for (var prop in mixin) {
        if (mixin.hasOwnProperty(prop)) {
            this.prototype[prop] = mixin[prop]; // this is where the error occurs: 'TypeError: this.prototype is undefined'
        }
    }
};

// Define File prototype
var File = Object.create(Object.prototype);
defineProperty(File, 'file', null);
defineProperty(File, 'outputID', null);
defineProperty(File, 'hash', null);
defineProperty(File, 'hashThis', function (callback) {});

// define Timestamp prototype
var Timestamp = Object.create(File);
defineProperty(Timestamp, 'protectedHashValue', null);
defineProperty(Timestamp, 'timestamp', null);
defineProperty(Timestamp, 'read', function () {});
defineProperty(Timestamp, 'verify', function () {});

// Later, we take in a file using the HTML5 file API
// First, create the File object (in an array because there are multiple files)
globalStatus.files[fileIndex] = Object.create(File);
// and now place the file in the file property of the new File object
globalStatus.files[fileIndex].file = evt.target.files[fileIndex];

// Later on we determine that a particular file is a timestamp
// We want to mix in the properties of the Timestamp prototype to this existing File object
globalStatus.files[fileIndex].addMixin(Timestamp); // this is the call which initiates the error
user2700751
  • 87
  • 1
  • 1
  • 6
  • Well, the `File` instance that is placed in your array (on which you call the `addMixin` method) does not have a `.prototype` property. Why do you expect it to do? – Bergi Jan 16 '14 at 19:34
  • 1
    [Do not mess up `Object.prototype`!](http://stackoverflow.com/q/13296340/1048572) – Bergi Jan 16 '14 at 19:36
  • When you mix classical inheritance and prototypal inheritance you are asking for troubles. But if you really want to shoot yourself in the foot try this.constructor.prototype. – mpm Jan 16 '14 at 19:37
  • Why are you using that obscure `defineProperty` method if you could simply use dot notation? – Bergi Jan 16 '14 at 19:38

1 Answers1

2

Inside addMixin method this refers to an object instance, on which the method was invoked. Instances do not have a prototype property - Functions do.

I am not exactly sure, what you are trying to do: to add mixin properties to all future instances or to add them to an instance, so I'll provide you with both variants.

For all instances, what you need to use is a constructor property, which returns a function, that was used to create an instance:

Object.prototype.addMixin = function (mixin) {    
    for (var prop in mixin) {
        if (mixin.hasOwnProperty(prop)) {
            this.constructor.prototype[prop] = mixin[prop]; 
        }
    }
};

For a specific instance, simply use bracket notation on this:

Object.prototype.addMixin = function (mixin) {    
    for (var prop in mixin) {
        if (mixin.hasOwnProperty(prop)) {
            this[prop] = mixin[prop];
        }
    }
};

Beware of properties of mixin parameter, that are reference types (e.g. object Object or object Array)

Artyom Neustroev
  • 8,627
  • 5
  • 33
  • 57
  • Yes, meant to change that specific instance. Your answer makes good sense, this is my first time doing properly OOP JavaScript. – user2700751 Jan 16 '14 at 19:40
  • How do you feel about adding the Mixin function to Object.prototype? Bergi does not like/recommend it. – user2700751 Jan 16 '14 at 19:40
  • @user2700751: I'm fine with it, but you need to make it non-enumerable (via `Object.defineProperty` which you already know). – Bergi Jan 16 '14 at 19:44
  • @user2700751 Bergi is right. Another option is to implement your own base class with `addMixin` method and inherit from it, not from `Object` directly. – Artyom Neustroev Jan 17 '14 at 09:24