Home >Web Front-end >JS Tutorial >Three ways and examples of inheritance in JavaScript_javascript skills
Although JavaScript is an object-oriented language, its inheritance mechanism is different from other traditional object-oriented languages from the beginning. It is a prototype-based inheritance mechanism, but under this mechanism, inheritance is still There are a few different ways to implement this.
Method 1: Class inheritance
The so-called class inheritance refers to the inheritance method that imitates traditional object-oriented languages. Both the inheriting and the inherited are "classes". The code is as follows:
First define a parent class (or super class):
function Person(name){ this.name=name; } Person.prototype.getName=function(){ return this.name; };
The attributes of the parent class person are defined in the constructor, which ensures that the name attribute of the subclass that inherits it does not share this attribute with it, but belongs to the subclass alone. The getName method is mounted on the prototype to Let multiple instances of its subclasses share this method body, which can save memory. (For multiple instances, every time a New instance comes out, it will be ensured that the getName method of these instances refers to the same memory space. rather than a separate space).
Define an inheritance method extend as follows:
function extend(subClass,superClass){ var F=function(){}; F.prototype=superClass.prototype; subClass.prototype=new F(); subClass.prototype.constructor=subClass; subClass.superClass=superClass.prototype; if(superClass.prototype.constructor==Object.prototype.constructor){ superClass.prototype.constructor=superClass; } }
In this method, first create a new class F, make its prototype the prototype of the parent class, and let the prototype of the subclass point to an instance of the class F, thereby achieving the purpose of inheriting the parent class , at the same time, because the prototype of the subclass has been modified, the constructor attribute of the modified prototype is pointed to the subclass, so that it has a constructor, and at the same time, a superClass attribute is mounted to the subclass, through which the subclass can call the parent class. , thus establishing the relationship between the subclass and the parent class.
Define a subclass Author to inherit the parent class Person, as follows:
function Author(name,books){ Author.superClass.constructor.call(this,name); this.book=books; } extend(Author,Person); Author.prototype.getBooks=function(){ return this.book; }
Here, in the constructor of the subclass, the constructor of the parent class is called through its superClass attribute, and the call method is used to convert the this pointer called by the method, so that the subclass Author also owns (inherits) the attributes of the parent class, and at the same time The subclass also has its own attribute book, so in the constructor, the parameter books is assigned to the attribute book to achieve the purpose of construction. Use the extend function to inherit the properties and methods on the prototype of the parent class Person (actually only the methods are inherited, because we only mounted the methods to the prototype before, and the properties were defined in the constructor). At the same time, Author has its own method getBooks, which is mounted on the corresponding prototype, achieving the purpose of further expanding itself on the basis of inheritance.
This inheritance method obviously uses class inheritance similar to traditional object-oriented languages. The advantage is that it is easy to understand for programmers who are accustomed to traditional object-oriented concepts. The disadvantage is that the process is more cumbersome and the memory consumption is slightly larger. , because the subclass also has its own constructor and prototype, and the properties of the subclass and the parent class are completely isolated. Even if the two have the same value, they cannot share the same memory.
Method 2: Prototypal inheritance
First define a parent class. This will not deliberately imitate the use of constructors to define, but directly use object literals to define an object, which is the parent class
var Person={ name:'default name', getName:function(){ return this.name; } } ;
Same as the first method, this object has an attribute name and a method getName.
Then define a clone method to realize the inheritance of the subclass from the parent class, as follows:
function clone(obj){ function F(){} F.prototype=obj; return new F(); }
This cloning method creates a new object, points the prototype of the object to the parent class, which is the parameter obj, and returns the object at the same time.
Finally, the subclass inherits the parent class through the clone function, as follows:
var Author=clone(Person); Author.book=['javascript']; Author.showBook=function(){ return this.book; }
这里定义一个子类,通过clone函数继承父类Person,同时拓展了一个属性book,和一个方法showBook,这里该子类也拥有属性name,但是它和父类的name值是一样的,所以没有进行覆盖,如果不一样,可以采用
Author.name='new name';覆盖这个属性,从而得到子类的一个新的name属性值。
这种原型式继承相比于类式继承更为简单自然,同时如果子类的属性和父类属性值相同,可以不进行修改的话,那么它们两者其实共享的是同一段内存空间,如上面的name属性,缺点是对于习惯了传统面向对象的程序员难以理解,如果两者要进行选择的话,无疑是这种方式更为优秀一些。
既然javascript中采用基于原型的方式来实现继承,而且每个对象的原型只能指向某个特定的类的实例(不能指向多个实例),那么如何实现多重继承(即让一个类同时具有多个类的方法和属性,而且本身内部不自己定义这些方法和属性)?
在javascript设计模式中给出了一种掺元类(mixin class)的方式:
首先定义一个掺元类,用来保存一些常用的方法和属性,这些方法和属性可以通过拓展的方式添加到任何其他类上,从而被添加类就具有了该类的某些方法和属性,如果定义多个掺元类,同时添加给一个类,那么该类就是间接实现了“多重继承”,基于这种思想,实现如下:
掺元类定义:
var Mixin=function(){}; Mixin.prototype={ serialize:function(){ var output=[]; for(key in this){ output.push(key+":"+this[key]); } return output.join(','); } }
该掺元类具有一个serialize方法,用来遍历其自身,输出自身的属性和属性值,并且将他们以字符串形式返回,中间用逗号隔开。
定义一个扩充方法,用来使某个类经过扩充之后具备掺元类的属性或方法,如下:
function augment(receivingClass,givingClass){ if(arguments[2]){ for(var i= 2,len=arguments.length;i<len;i++){ receivingClass.prototype[arguments[i]]=givingClass.prototype[arguments[i]]; } } else { for(methodName in givingClass.prototype){ if(!receivingClass.prototype[methodName]){ receivingClass.prototype[methodName]=givingClass.prototype[methodName]; } } } }
该方法默认是两个参数,第一个参数是接受被扩充的类,第二个参数是掺元类(用来扩充其他类的类),还可以有其他参数,如果大于两个参数,后面的参数都是方法或者属性名,用来表示被扩充类只想继承掺元类的指定的属性或方法,否则默认继承掺元类的所有属性和方法,在该函数中,第一个if分支是用来继承指定属性和方法的情形,else分支是默认继承所有属性和方法的情形。该方法的实质是将掺元类的原型上的属性和方法都扩充(添加)到了被扩充类的原型上面,从而使其具有掺元类的属性和方法。
最后,使用扩充方法实现多重继承
augment(Author,Mixin); var author= new Author('js',['javascript design patterns']); alert(author.serialize());
这里定义了一个author的类,该类继承自Person父类,同时又具备掺元类Mixin的方法和属性,如果你愿意,可以定义N个掺元类用来扩充该类,它同样能够继承你定义的其他掺元类的属性和方法,这样就实现了多重继承,最后,author的serialize方法的运行结果如下:
你会发现该类同时具有person类,Author类,Mixin类的属性和方法,其中Person和Mixin的属性和方法都是通过“继承”得来的,从实际上来讲,它实现了多重继承。