OOP In javascript

2019-02-10 21:03发布

问题:

Im wondering which way of using OOP in Javascript ist best way to go with.

There is this prototype thing and you have the function style way. But both have very bad ways to inherit a base class.

So I tried to build a way to make this possible without having to use prototype and such.

function Car(name) {
    this.Name = name;

    this.FullName = function () {
        return this.Name;
    }
}

function SpecialCar(name, variant) {
    //BaseClass.apply(this, PARAMS AS ARRAY);
    Car.apply( this, [name] );

    //new property
    this.Variant = variant;

    //override function
    this.FullName = function () {
        return this.Name + " " + this.Variant ;
    }
}

var audi = new Car("audi");
$("#result").append(audi.FullName() + "<br>");

var audia3 = new SpecialCar("audi", "a3");
$("#result").append(audia3.FullName()+ "<br>");

You can check the jsFiddle here: http://jsfiddle.net/vu9ZF/2/

Is this okay or is it just bad-practice?

Would be very nice to get some answers why other ways are better because I just dont get it.

EDIT: Thank you all for answering me so fast! I was trying to find some way of OOP in javascript for myself, not answering on how to do oop in javascript. I dont like the way of using prototype for that because im using c# most of my worktime and its a bit confusing to switch between "c#-like oop" and "prototype oop". But someone in the comments told me that avoiding prototype isnt a good idea, soo ill drop that.

Thanks stackoverflow your all awesome & saved me so much time =)

回答1:

This is how it's done:

function Car ( name ) {
    this.name = name;
}

Car.prototype.fullName = function () {
    return this.name;
}

function SpecialCar ( name, variant ) {
    Car.apply( this, arguments );
    this.variant = variant;
}

SpecialCar.prototype = Object.create( Car.prototype );

SpecialCar.prototype.fullName = function () {
    return this.name + ' ' + this.variant;
}; 

(You need to shim Object.create for IE8)

Live demo: http://jsfiddle.net/3Rehr/


So, the methods should be assigned to the constructor's prototype object, not to the instances themselves.

Also, in order to pre-process the instance with the super-constructor, simply do this:

Car.apply( this, arguments );

so the this.base thing is not needed.



回答2:

It's not particularly recommandable because you actually return a Car instance and not a SpecialCar instance.

audia3 instanceof Car === true;
audia3 instanceof SpecialCar === false;

This is confusing because you do execute new SpecialCar. Also properties of SpecialCar.prototype wouldn't be available on the instance, but you seem to be using a custom inheritance copying pattern.



回答3:

The way I usually go is the one described in this page

It gives the code a more structured link, even thou I like the feature in your code of being able to call the parent's constructor.

function Car( name ) {
  this.Name = name;
}

Car.prototype.FullName = function FullName() {
  return this.Name;
}


function SpecialCar( name, variant ) {
  this.Name = name;
  this.Variant = variant;
}

SpecialCar.prototype = new Car();
SpecialCar.constructor = SpecialCar;

SpecialCar.prototype.FullName = function FullName() {
  return this.Name + " " + this.Variant; 
}


回答4:

As far as the constructor pattern goes, I actually prefer your method, rather than using apply or anything similar. It might get a little confusing due to the necessity of return, but it doesn't feel quite as dirty as apply to me.

However, I prefer using prototypal inheritance a little more directly, with Object.create:

var Car = {
    fullName: function() {
        return this.name;
    }
}

var SpecialCar = Object.create(Car);
SpecialCar.fullName = function() {
    return this.name + ' ' + this.variant;
};

var audi = Object.create(Car);
audi.name = 'audi';

var audiA3 = Object.create(SpecialCar);
audiA3.name = 'audi';
audiA3.variant = 'A3';

Some browsers don't support Object.create natively, but it is shimmable.



回答5:

This is how I would do it. Needs some sugar code for it to work. You can find OoJs on github. OoJs covers most of the OOP features from C++, except for multiple inheritance and enforcing pure virtual functions...

;( function class_Car( namespace )
{
    'use strict';

    if( namespace.Car ) return    // protect against double inclusions

        namespace.Car = Car
    var Static        = TidBits.OoJs.setupClass( namespace, "Car" )


    // constructor
    //
    function Car( name )
    {
        this.Name = name               // data member, private by default

        return this.Public( FullName ) // method FullName will be public
    }


    function FullName()
    {
        return this.Name;
    }

})( window )




;( function class_SpecialCar( namespace )
{
    'use strict';

    if( namespace.SpecialCar ) return    // protect against double inclusions

        namespace.SpecialCar = SpecialCar
    var Static               = TidBits.OoJs.setupClass( namespace, "SpecialCar", "Car" )


    // constructor
    //
    function SpecialCar( name, variant )
    {
        this.Super( name )

        this.Variant = variant

        return this.Public( FullName )
    }


    function FullName()
    {
        return this.Car.FullName() + " " + this.Variant
    }

})( window )


var audi = new Car("audi");
$("#result").append(audi.FullName() + "<br>"); // output: audi

var audia3 = new SpecialCar("audi", "a3");
$("#result").append(audia3.FullName()+ "<br>"); // output: audi a3