可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
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