admin管理员组

文章数量:1317906

I want to create a Javascript class/object that allow me to have various method:

Model class

  • Model.all() » static method
  • Model.find() » static method
  • Model delete() » instance method
  • Model save() » instance method
  • Model.create() » static that returns a new Model instance

For static method I can define them using:

Model.staticMethod(){ method }

while for instance method is better to use:

function Model(){
    this.instanceMethod = function(){}    
}

and then create a new instance

or using prototype?

var m = function Model(){

}

m.prototype.method() = function() {
}

Now let's say that I want to create a new class based on Model, how to inherit not only its prototypes but also its static methods?

EDIT:

to avoid confusion this is more or less what I want to create:

.html and .html

where I can define a new model using something like that

var User = ActiveRecord.create({
    username: '',
    password: '',
    post_count: 0,
    profile: ''
}

then create an instance

var jessica = User.create({
    username: "Jessica",
    password: "rabbit"
});

use instance methods like

jessica.save();

but also class methods:

User.findByUsername('Jessica');

I want to create a Javascript class/object that allow me to have various method:

Model class

  • Model.all() » static method
  • Model.find() » static method
  • Model delete() » instance method
  • Model save() » instance method
  • Model.create() » static that returns a new Model instance

For static method I can define them using:

Model.staticMethod(){ method }

while for instance method is better to use:

function Model(){
    this.instanceMethod = function(){}    
}

and then create a new instance

or using prototype?

var m = function Model(){

}

m.prototype.method() = function() {
}

Now let's say that I want to create a new class based on Model, how to inherit not only its prototypes but also its static methods?

EDIT:

to avoid confusion this is more or less what I want to create:

http://activejs/activerecord/index.html and http://activejs/activerecord/ActiveRecord/Model/index.html

where I can define a new model using something like that

var User = ActiveRecord.create({
    username: '',
    password: '',
    post_count: 0,
    profile: ''
}

then create an instance

var jessica = User.create({
    username: "Jessica",
    password: "rabbit"
});

use instance methods like

jessica.save();

but also class methods:

User.findByUsername('Jessica');
Share Improve this question edited Jun 7, 2016 at 20:36 marc_s 756k184 gold badges1.4k silver badges1.5k bronze badges asked Jun 19, 2012 at 8:57 Matteo PagliazziMatteo Pagliazzi 5,27012 gold badges51 silver badges85 bronze badges 9
  • Yes you should use prototype, otherwise you create new function objects for every object you instantiate. – Esailija Commented Jun 19, 2012 at 9:05
  • possible duplicate of Use of 'prototype' vs. 'this' in Javascript? – Felix Kling Commented Jun 19, 2012 at 9:11
  • Regarding your last question, you probably have to iterate over the methods you added to Model and assign them to the new class as well. – Felix Kling Commented Jun 19, 2012 at 9:14
  • so not something referred to the whole class? because to me seems a bit strange to do var a = new Model() and then a.all since a represents a single istance it shouldn't be used to get all the models from the server (all() should do this) – Matteo Pagliazzi Commented Jun 19, 2012 at 9:16
  • 2 There are no real static methods. Everything is an object and everything can have properties. If you assign Model.all = ..., then later you call Model.all(). var a = new Model(); a.all() would not even work. Or maybe you misunderstood my ment and I yours. – Felix Kling Commented Jun 19, 2012 at 9:27
 |  Show 4 more ments

4 Answers 4

Reset to default 5
function Model() {}

// Methods in the instantiated object
Model.prototype = {
    constructor: Model,

    // Note that "delete" is a reserved word, so we need quotes
    'delete': function() {},

    save: function() {}
};

// Static methods
Model.all = function() {};

Model.find = function() {};

Model.create = function() {
    return new Model();

    // To be more generic, you can also:
    return new this();
};

When you use var InheritedModel = Object.create( Model );, it also inherits the static methods.

var InheritedModel = Object.create( Model );
!!InheritedModel.all // true

However, you can't do new InheritedModel(), because it's not a function, and using Object.create( InheritedModel ) won't give you the instance methods.

If you want to instantiate the inherited class using new, you need the following:

function InheritedModel() {}

InheritedModel.prototype = Object.create( Model.prototype );

// Copy all the static methods in the InheritedModel object
Object.keys( Model ).forEach( function( key ) {
    InheritedModel[ key ] = Model[ key ];
} );

Edit: after seeing your edit, here is the solution I'd remend you:

function ActiveRecord( type, args ) {
    if ( type = 'users' ) {
        return new this.users();
    }
}

// Static method on ActiveRecord
ActiveRecord.create = function( type, args ) {
    return new ActiveRecord( type, args );
};

ActiveRecord.prototype = {
    constructor: ActiveRecord,

    // Instance method on ActiveRecord, you won't need it,
    // but your constructor does
    users: function( args ) {}
};

var Users = ActiveRecord.prototype.users;

Users.prototype = {
    constructor: Users,

    // Instance method on User's instance
    save: function() {}
}

// Static method on User
Users.create = function() {}

Commented code is pseudo code. You can achieve the same by:

var modelInstanceMethods = {

    save: function() {
        /*
        insert into this.tableName blabla
        */
    },

    'delete': function() {
        /*
        delete from this.tableName blabla
        */
    }
};

var modelStatics = {

    create: function(obj) {
        return new this(obj);
    },

    all: function() {
        /*
        return select * from this.tableName.map( function( values ) {
            return new this(values);
        },this);
        */
    },

    find: function(id) {
        /*
        select * from this.tableName where id = id
        return new this(columnValues);
        */
    }


};

var ActiveRecord = {
    create: function( tableName, fields, methods ) {

        function Model( obj ) {
            this.tableName = tableName;
            this.fields = {};
            if( fields ) {
                for( var field in fields ) {
                    this.fields[field] = fields[field];
                }
            }

            if( obj ) {
                for( var field in obj ) {
                    this.fields[field] = obj[field];
                }       
            }
        }

        Model.tableName = tableName;
        Model.prototype = Object.create(modelInstanceMethods);
        Model.prototype.constructor = Model;

        for( var key in modelStatics ) {
            Model[key] = modelStatics[key];
        }

        if( methods ) {
            for( var key in methods ) {
                Model.prototype[key] = methods[key];
            }   
        }

        return Model;
    }
};

Usage

var User = ActiveRecord.create('users',
    /* fields and their default values */
{
    id: 0,
    username: '',
    password: '',
    post_count: 0,
    profile: ''
}, {
    /*instance methods */
    setPassword: function(password) {
        this.fields.password = password;
    }
});

/*You can define static methods like this */

User.findByUsername = function(username) {
    /*select from this.tableName where userName = username
               return new this(columnValues) blabla
             */
};

var jessica = User.create( {
    username: "Jessica",
    password: "rabbit"
});

jessica.save();

User.findByUsername('Jessica');

You can extend the Object's prototype adding an "extends" method to Object.prototype. This way you will have an inherithance method that look like java.

(it's important to define the "extends" property as not enumerable otherwise it will break jQuery)

Object.defineProperty(Object.prototype, "extends", {
        "enumerable": false,
        "value" : function(constructor) {

                /*Inheriting enumerable statick method and paramether
                from the super class */
                Object.keys( constructor ).forEach( function(key) {
                        this[key]= constructor[key];
                }.bind(this));

                /*Classic Javascript inheritance*/
                this.prototype= Object.create( constructor.prototype, {
                            "constructor": {
                                    "value": this,
                                    "configurable": true
                            }
                });             

                this.__super__= constructor;

        }

});

After you can easily inherit one class by an other by doing so:

InheritedModel.extends(Model);

function InheritedModel(params){

       this.constructor.__super__.call(this, params);

       /* Or directly :
       Model.call(this,param);
       */

       /*Code specific to InheritedModel constructor */
}

/*To overload method from the super class:*/

InheritedModel.prototype.foo= function(params){

     var out= this.constructor.__super__.prototype.foo.call(this,params);

     /* Or
     var out= Model.prototype.foo.call(this,param);
     */

     /* code */

};

InheritedModel will inherit of all the instance method and all static method from model.

Example:

function Model() {
        this.inheritedClassName= "Model";
};

Model.inheritedClassName= "Model";

Model.getClassName = function() {
       return this.name;
};

Model.prototype.getClassName = function() {
        return this.constructor.name;
};

InheritedModel.extends(Model);

function InheritedModel() {
        Model.call(this);
}

console.log(InheritedModel.inheritedClassName);/* Model */
console.log(InheritedModel.getClassName());/* InheritedModel */

var inheritedModel= new InheritedModel();

console.log(inheritedModel.inheritedClassName);/* Model */
console.log(inheritedModel.getClassName());/* InheritedModel */

I think this is the best solution.

what about this, you have private and public methods:

function Model() {
    var privateMethods = {
       private1: function() {},
       private2: function() {},
       private3: function() {},
    };

    var publicMethods = {
    method1: function() {},
    method2: function() {
            //call a private method...
            privateMethods.private1();
        }
    };

    return publicMethods;
}


// Static methods
Model.all = function() {};

Model.find = function() {};

Model.create = function() {
    return new Model();
};

本文标签: oopJavascript static method inheritanceStack Overflow