zanona
zanona

Reputation: 12717

create a new instance of bind generated obj

I am creating a new class based on the Base class binded with external methods from the ext obj.

function Base(info) {
    var self = this;
    self.name = info.name;
    self.createNewInstance = function (data) {
        //I would like to identify the parent constructor
        // in this case, the obj containing `filter` and `find` methods
        // and use that to generate a new instance
        return new self.constructor(data);
    };
    return self;
}

var ext = {
        filter: function () {/*...*/},
        find: function () {/*...*/}
    },
    FinalClass = Base.bind(ext),
    instance1 = FinalClass({name: 'John'}),
    instance2 = instance1.createNewInstance({name: 'Mark'});

console.log(instance1); 
//--> {name: 'John', filter: [Function], find: [Function], createNewInstance: [Function]}
console.log(instance2); 
//--> {name: 'Mark'}

But as you can see I would like to create new instance from inside the FinalClass class which will be able to use the binded methods and not only the Base class ones. So instance2 would also have filter, find and createNewInstance methods.

I would be using different types of classes that inherit the same Base class, so just hardcode the bind method in there wouldn't work I'm afraid :(

Is this possible to achieve?

Thanks in advance

Upvotes: 1

Views: 588

Answers (1)

ZER0
ZER0

Reputation: 25332

I'm afraid there some misunderstanding about how javascript works. Let's analyze the code:

var ext = {
        filter: function () {/*...*/},
        find: function () {/*...*/}
    },
    FinalClass = Base.bind(ext),

So, here you have a Base function bound to ext. It means, every time you call FinalClass, this will be ext.

    instance1 = FinalClass({name: 'John'}),

Here you're call FinalClass passing an object with name equal to 'John'. Because in Base you have:

function Base(info) {
    var self = this;
    self.name = info.name;
    // ...
    return self;
}

And this is the instance of ext in FinalClass, it means you're adding a new property name to ext object. And I think you don't want that. Then you returns self, it means you're returning ext again.

After that, you have:

    instance2 = instance1.createNewInstance({name: 'Mark'});

Let's have a look to that method:

self.createNewInstance = function (data) {
    return new self.constructor(data);
};

Because instance1 it wasn't create using new operator, and it's ext itself, it means its constructor is Object, not FinalClass as you probably expected.

I believe you can find a better way to do what you want using prototypal inheritance and Object.create. However, you should be able to obtain the result you're looking for using a code similar to the follow:

function Base(info) {
    this.name = info.name;

    this.createNewInstance = function (data) {
        return new this.constructor(data);
    };

    return this;
}

var ext = {
        filter: function () {/*...*/},
        find: function () {/*...*/}
    };

function FinalClass(info) {
    var object = Object.create(ext);
    object.constructor = FinalClass;

    return Base.call(object, info);
}

var instance1 = FinalClass({name: 'John'}),
    instance2 = instance1.createNewInstance({name: 'Mark'});

console.log(instance1);
console.log(instance2);
// notice that `filter` and `find` won't probably be listed because are not "own properties", but the objects have them:
console.log(instance1.filter);
console.log(instance2.filter);

You could also write a utility method in Base that generalize a bit that work, so your code will looks like:

function Base(info) {
    this.name = info.name;

    this.createNewInstance = function (data) {
        return new this.constructor(data);
    };

    return this;
}

Base.create = function(extension) {
    return function Extendend () {
        var object = Object.create(extension);
        object.constructor = Extendend;

        return Base.apply(object, arguments);
    }
}

var ext = {
        filter: function () {/*...*/},
        find: function () {/*...*/}
    };

var FinalClass = Base.create(ext);

var instance1 = FinalClass({name: 'John'}),
    instance2 = instance1.createNewInstance({name: 'Mark'});

Hope it helps, if you have doubts or I misunderstood your question, just let me know!

Upvotes: 2

Related Questions