是否可以在JavaScript中模拟抽象基类?最优雅的方式是什么?
说,我想做一些事情: -
var cat = new Animal('cat'); var dog = new Animal('dog'); cat.say(); dog.say();
应输出:'bark','meow'
创建抽象类的一种简单方法是:
/** @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
方法都是抽象的.
创建实例会引发错误:
new Animal(); // throws
这就是你如何"继承"它:
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
根据ES6,您可以使用JavaScript类和继承来完成您的需要.
ECMAScript 2015中引入的JavaScript类主要是基于JavaScript现有基于原型的继承的语法糖.
参考:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes
首先,我们定义抽象类.此类无法实例化,但可以扩展.我们还可以定义必须在扩展此类的所有类中实现的函数.
/**
* Abstract Class Animal.
*
* @class Animal
*/
class Animal {
constructor() {
if (this.constructor == Animal) {
throw new Error("Abstract classes can't be instantiated.");
}
}
say() {
throw new Error("Method 'say()' must be implemented.");
}
eat() {
console.log("eating");
}
}
之后,我们可以创建我们的具体类.这些类将继承抽象类的所有函数和行为.
/**
* Dog.
*
* @class Dog
* @extends {Animal}
*/
class Dog extends Animal {
say() {
console.log("bark");
}
}
/**
* Cat.
*
* @class Cat
* @extends {Animal}
*/
class Cat extends Animal {
say() {
console.log("meow");
}
}
/**
* Horse.
*
* @class Horse
* @extends {Animal}
*/
class Horse extends Animal {}
结果......
// RESULTS
new Dog().eat(); // eating
new Cat().eat(); // eating
new Horse().eat(); // eating
new Dog().say(); // bark
new Cat().say(); // meow
new Horse().say(); // Error: Method say() must be implemented.
new Animal(); // Error: Abstract classes can't be instantiated.
您可以查看Dean Edwards的基础课程:http://dean.edwards.name/weblog/2006/03/base/
或者,道格拉斯·克罗克福德(Douglas Crockford)就JavaScript中的经典继承提供了这个例子/文章: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__
它不是标准变量,但它至少在Firefox和Safari中有效。
如果您不了解它的工作原理,请阅读原型链。
您可以使用对象原型创建抽象类,一个简单的示例可以如下所示:
var SampleInterface = { addItem : function(item){} }
您可以更改上述方法,实现时可由您自行决定.如需详细观察,您可以访问此处.
问题已经很老了,但我创建了一些可能的解决方案,如何创建抽象的"类"并阻止创建类型的对象.
//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();