如何在JavaScript中创build抽象基类?

是否有可能在JavaScript中模拟抽象基类? 什么是最优雅的方式来做到这一点?

说,我想做一些事情: –

var cat = new Animal('cat'); var dog = new Animal('dog'); cat.say(); dog.say(); 

它应该输出:“树皮”,“喵”

一个简单的方法来创build一个抽象类是这样的:

 /** @constructor @abstract */ var Animal = function() { if (this.constructor === Animal) { throw new Error("Can't instantiate abstract class!"); } // Animal initialization... }; /** @abstract */ Animal.prototype.say = function() { throw new Error("Abstract method!"); } 

Animal “阶级”和say是抽象的。

创build一个实例会抛出一个错误:

 new Animal(); // throws 

这就是你如何“inheritance”它:

 var Cat = function() { Animal.apply(this, arguments); // Cat initialization... }; Cat.prototype = Object.create(Animal.prototype); Cat.prototype.constructor = Cat; Cat.prototype.say = function() { console.log('meow'); } 

Dog看起来就像它。

这是你的场景如何发挥:

 var cat = new Cat(); var dog = new Dog(); cat.say(); dog.say(); 

小提琴在这里 (查看控制台输出)。

你的意思是这样的:

 function Animal() { //Initialization for all Animals } //Function and properties shared by all instances of Animal Animal.prototype.init=function(name){ this.name=name; } Animal.prototype.say=function(){ alert(this.name + " who is a " + this.type + " says " + this.whattosay); } Animal.prototype.type="unknown"; function Cat(name) { this.init(name); //Make a cat somewhat unique var s=""; for (var i=Math.ceil(Math.random()*7); i>=0; --i) s+="e"; this.whattosay="Me" + s +"ow"; } //Function and properties shared by all instances of Cat Cat.prototype=new Animal(); Cat.prototype.type="cat"; Cat.prototype.whattosay="meow"; function Dog() { //Call init with same arguments as Dog was called with this.init.apply(this,arguments); } Dog.prototype=new Animal(); Dog.prototype.type="Dog"; Dog.prototype.whattosay="bark"; //Override say. Dog.prototype.say = function() { this.openMouth(); //Call the original with the exact same arguments Animal.prototype.say.apply(this,arguments); //or with other arguments //Animal.prototype.say.call(this,"some","other","arguments"); this.closeMouth(); } Dog.prototype.openMouth=function() { //Code } Dog.prototype.closeMouth=function() { //Code } var dog = new Dog("Fido"); var cat1 = new Cat("Dash"); var cat2 = new Cat("Dot"); dog.say(); // Fido the Dog says bark cat1.say(); //Dash the Cat says M[e]+ow cat2.say(); //Dot the Cat says M[e]+ow alert(cat instanceof Cat) // True alert(cat instanceof Dog) // False alert(cat instanceof Animal) // True 

你可能想看看迪安·爱德华兹的基本类: http : //dean.edwards.name/weblog/2006/03/base/

或者,Douglas Crockford也有关于JavaScript中经典inheritance的示例/文章: http : //www.crockford.com/javascript/inheritance.html

是否有可能在JavaScript中模拟抽象基类?

当然。 在JavaScript中有大约一千种实现类/实例系统的方法。 这里是一个:

 // Classes magic. Define a new class with var C= Object.subclass(isabstract), // add class members to C.prototype, // provide optional C.prototype._init() method to initialise from constructor args, // call base class methods using Base.prototype.call(this, ...). // Function.prototype.subclass= function(isabstract) { if (isabstract) { var c= new Function( 'if (arguments[0]!==Function.prototype.subclass.FLAG) throw(\'Abstract class may not be constructed\'); ' ); } else { var c= new Function( 'if (!(this instanceof arguments.callee)) throw(\'Constructor called without "new"\'); '+ 'if (arguments[0]!==Function.prototype.subclass.FLAG && this._init) this._init.apply(this, arguments); ' ); } if (this!==Object) c.prototype= new this(Function.prototype.subclass.FLAG); return c; } Function.prototype.subclass.FLAG= new Object(); 

var cat = new Animal('cat');

当然,这不是一个抽象的基础类。 你的意思是:

 var Animal= Object.subclass(true); // is abstract Animal.prototype.say= function() { window.alert(this._noise); }; // concrete classes var Cat= Animal.subclass(); Cat.prototype._noise= 'meow'; var Dog= Animal.subclass(); Dog.prototype._noise= 'bark'; // usage var mycat= new Cat(); mycat.say(); // meow! var mygiraffe= new Animal(); // error! 
 Animal = function () { throw "abstract class!" } Animal.prototype.name = "This animal"; Animal.prototype.sound = "..."; Animal.prototype.say = function() { console.log( this.name + " says: " + this.sound ); } Cat = function () { this.name = "Cat"; this.sound = "meow"; } Dog = function() { this.name = "Dog"; this.sound = "woof"; } Cat.prototype = Object.create(Animal.prototype); Dog.prototype = Object.create(Animal.prototype); new Cat().say(); //Cat says: meow new Dog().say(); //Dog says: woof new Animal().say(); //Uncaught abstract class! 
 function Animal(type) { if (type == "cat") { this.__proto__ = Cat.prototype; } else if (type == "dog") { this.__proto__ = Dog.prototype; } else if (type == "fish") { this.__proto__ = Fish.prototype; } } Animal.prototype.say = function() { alert("This animal can't speak!"); } function Cat() { // init cat } Cat.prototype = new Animal(); Cat.prototype.say = function() { alert("Meow!"); } function Dog() { // init dog } Dog.prototype = new Animal(); Dog.prototype.say = function() { alert("Bark!"); } function Fish() { // init fish } Fish.prototype = new Animal(); var newAnimal = new Animal("dog"); newAnimal.say(); 

这不能保证工作,因为__proto__不是一个标准variables,但它至less在Firefox和Safari中起作用。

如果你不明白它是如何工作的,请阅读原型链。

你可以通过使用对象原型来创build抽象类,一个简单的例子可以如下:

 var SampleInterface = { addItem : function(item){} } 

你可以改变以上的方法,当你实现它时,取决于你。 详细的观察,你可能想要访问这里 。

问题是相当古老的,但我创造了一些可能的解决scheme如何创build抽象的“类”和块创buildtypes的对象。

 //our Abstract class var Animal=function(){ this.name="Animal"; this.fullname=this.name; //check if we have abstract paramater in prototype if (Object.getPrototypeOf(this).hasOwnProperty("abstract")){ throw new Error("Can't instantiate abstract class!"); } }; //very important - Animal prototype has property abstract Animal.prototype.abstract=true; Animal.prototype.hello=function(){ console.log("Hello from "+this.name); }; Animal.prototype.fullHello=function(){ console.log("Hello from "+this.fullname); }; //first inheritans var Cat=function(){ Animal.call(this);//run constructor of animal this.name="Cat"; this.fullname=this.fullname+" - "+this.name; }; Cat.prototype=Object.create(Animal.prototype); //second inheritans var Tiger=function(){ Cat.call(this);//run constructor of animal this.name="Tiger"; this.fullname=this.fullname+" - "+this.name; }; Tiger.prototype=Object.create(Cat.prototype); //cat can be used console.log("WE CREATE CAT:"); var cat=new Cat(); cat.hello(); cat.fullHello(); //tiger can be used console.log("WE CREATE TIGER:"); var tiger=new Tiger(); tiger.hello(); tiger.fullHello(); console.log("WE CREATE ANIMAL ( IT IS ABSTRACT ):"); //animal is abstract, cannot be used - see error in console var animal=new Animal(); animal=animal.fullHello(); 

Javascript可以inheritance,请查看下面的URL:

http://www.webreference.com/js/column79/

安德鲁

你可能想强制执行的另一件事是确保你的抽象类没有被实例化。 你可以通过定义一个充当抽象类构造函数的FLAG函数来实现。 然后这将尝试构造将调用其构造函数包含exception的标志被抛出。 示例如下:

 (function(){ var FLAG_ABSTRACT = function(__class){ throw "Error: Trying to instantiate an abstract class:"+__class } var Class = function (){ Class.prototype.constructor = new FLAG_ABSTRACT("Class"); } //will throw exception var foo = new Class(); 

})()

在这种情况下,我们可以使用Factorydevise模式。 JavaScript使用prototypeinheritance父母的成员。

定义父类的构造函数。

 var Animal = function() { this.type = 'animal'; return this; } Animal.prototype.tired = function() { console.log('sleeping: zzzZZZ ~'); } 

然后创build儿童class。

 // These are the child classes Animal.cat = function() { this.type = 'cat'; this.says = function() { console.log('says: meow'); } } 

然后定义子类的构造函数。

 // Define the child class constructor -- Factory Design Pattern. Animal.born = function(type) { // Inherit all members and methods from parent class, // and also keep its own members. Animal[type].prototype = new Animal(); // Square bracket notation can deal with variable object. creature = new Animal[type](); return creature; } 

testing它。

 var timmy = Animal.born('cat'); console.log(timmy.type) // cat timmy.says(); // meow timmy.tired(); // zzzZZZ~ 

下面是整个示例代码的Codepen链接 。

我想所有的答案都是特别的前两个(由一些和jordão )用传统的原型基JS概念来清晰地回答问题。
现在当你想让动物类的构造函数根据传递给构造的参数来行为的时候,我认为这与Creational Patterns (例如工厂模式)的基本行为非常相似。

在这里,我做了一个小小的方法来使它工作。

 var Animal = function(type) { this.type=type; if(type=='dog') { return new Dog(); } else if(type=="cat") { return new Cat(); } }; Animal.prototype.whoAreYou=function() { console.log("I am a "+this.type); } Animal.prototype.say = function(){ console.log("Not implemented"); }; var Cat =function () { Animal.call(this); this.type="cat"; }; Cat.prototype=Object.create(Animal.prototype); Cat.prototype.constructor = Cat; Cat.prototype.say=function() { console.log("meow"); } var Dog =function () { Animal.call(this); this.type="dog"; }; Dog.prototype=Object.create(Animal.prototype); Dog.prototype.constructor = Dog; Dog.prototype.say=function() { console.log("bark"); } var animal=new Animal(); var dog = new Animal('dog'); var cat=new Animal('cat'); animal.whoAreYou(); //I am a undefined animal.say(); //Not implemented dog.whoAreYou(); //I am a dog dog.say(); //bark cat.whoAreYou(); //I am a cat cat.say(); //meow 
 /****************************************/ /* version 1 */ /****************************************/ var Animal = function(params) { this.say = function() { console.log(params); } }; var Cat = function() { Animal.call(this, "moes"); }; var Dog = function() { Animal.call(this, "vewa"); }; var cat = new Cat(); var dog = new Dog(); cat.say(); dog.say(); /****************************************/ /* version 2 */ /****************************************/ var Cat = function(params) { this.say = function() { console.log(params); } }; var Dog = function(params) { this.say = function() { console.log(params); } }; var Animal = function(type) { var obj; var factory = function() { switch(type) { case "cat": obj = new Cat("bark"); break; case "dog": obj = new Dog("meow"); break; } } var init = function() { factory(); return obj; } return init(); }; var cat = new Animal('cat'); var dog = new Animal('dog'); cat.say(); dog.say(); 
 //Your Abstract class Animal function Animal(type) { this.say = type.say; } function catClass() { this.say = function () { console.log("I am a cat!") } } function dogClass() { this.say = function () { console.log("I am a dog!") } } var cat = new Animal(new catClass()); var dog = new Animal(new dogClass()); cat.say(); //I am a cat! dog.say(); //I am a dog!