javascript 面向对象编程之继承详解编程语言

构造函数、实例、原型之间的关系

每个函数都有一个prototype属性指向原型;原型内部有个constructor属性指向函数;实例有个_proto_ 指向原型,因为浏览器差异,有的浏览器不对外开放此属性。用一幅图简单描述如下(自己画的先凑活看吧^_^)

function Person(){
    
 
} 
var p1 = new Person(); 
console.log(Person==Person.prototype.constructor);//true

这里写图片描述

原型链

基于三者的关系,可以让子类的原型指向父类的实例,那么就能实现继承。

function Person(){
    
 
} 
Person.prototype.sayName=function(){
    
    console.log("person's sayName"); 
} 
 
function Student(){
    
 
} 
Student.prototype=new Person(); 
 
var s1 = new Student(); 
s1.sayName();

这里写图片描述
可以看到s1指向的原型就是Person实例,s1原型中含有constructor指向Person,还有_proto_指向Person prototype,在执行s1.sayName 时,首先在Student prototype寻找sayName函数,因为没有所以继续寻找上一级原型,Person prototype中有sayName,所以执行此方法。
这种方法实现的继承有个缺点就是无法往父类构造函数传参,为了解决此问题代码改为

借用构造函数

function Person(){ 
    this.colors=["red","blue","green"]; 
} 
 
function Student(){ 
    Person.call(this);//调用父类构造函数 
} 
var t1 = new Student(); 
t1.colors.push("black"); 
console.log(t1.colors);//[ 'red', 'blue', 'green', 'black' ] 
 
var t2 = new Student(); 
console.log(t2.colors);//[ 'red', 'blue', 'green' ]

这个模式的优点是可以传参,缺点就是,方法如果定义在构造函数中则犯了重复创造的毛病,所以可以将函数定义在原型上。结合原型链模式和构造函数模式,推出了组合模式。

组合模式

组合模式的思路是利用原型链来继承原型的属性和方法,利用构造函数模式继承父类的属性。

function Person(name){
    
    this.colors=["red","blue","green"]; 
    this.name=name; 
} 
Person.prototype.sayName=function(){
    
    console.log(this.name); 
} 
function Student(name,age){
    
    Person.call(this,name);//调用父类构造函数 
    this.age=age; 
} 
Student.prototype=new Person(); 
Student.prototype.sayAge=function(){
    
    console.log(this.age); 
} 
 
var t1 = new Student("jun",30); 
t1.colors.push("black"); 
console.log(t1.colors);//[ 'red', 'blue', 'green', 'black' ] 
t1.sayName();//jun 
t1.sayAge();//30 
 
var t2 = new Student("jordan",50); 
console.log(t2.colors);//[ 'red', 'blue', 'green' ] 
t2.sayName();//jordan 
t2.sayAge();//50 

组合模式既利用了原型模式也利用了构造函数模式,是目前最常用的继承模式。

原型式继承

原型式继承就是将子类原型指向父类实例的过程封装起来了,并且不用创建子类类型就可以实现继承,简化了代码;注意原型式继承就是实现了一个浅复制,如果有引用类型要注意。

function object(o){ 
    function F(){ 
 
    } 
    F.prototype=o; 
    return new F(); 
} 
 
var person={ 
    "name":"jordan", 
    "colors":["red","blue"] 
}; 
 
var o1 = object(person); 
o1.name="haha"; 
console.log(o1.name);//haha 
console.log(o1.colors);//[ 'red', 'blue' ] 
console.log(o1.hasOwnProperty("name"));//true,原型上的name 
o1.colors.push("black"); 
var o2=object(person); 
console.log(o2.name); 
console.log(o2.hasOwnProperty("name"));//false,实例上的name 
console.log(o2.colors)//[ 'red', 'blue', 'black' ]

寄生式继承

简单来说,就是封装了继承过程的代码,并做了增强,跟原型式继承差不多。缺点就是,增强函数无法复用。

function object(o){
    
    function F(){
    
 
    } 
    F.prototype=o; 
    return new F(); 
} 
 
function createAnother(original){
    
    var obj = object(o); 
    obj.someMethod=function(){
    
 
    } 
    return obj; 
}

寄生组合式继承

组合式继承最大的缺点是调用了两次超类型的构造方法,第一次是在Student.prototype=new Person(); 这会在Student的原型中创建一次属性,第二次是在new Student() 这会在Student实例中又创建了一次属性。寄生组合式继承的思路是,第一次调用超类构造函数的目的是为了获取超类原型的副本,可以通过复制一份超类原型去掉这一次。

function object(o){
    
    function F(){
    
 
    } 
    F.prototype=o; 
    return new F(); 
} 
 
function inheritPrototype(subType,superType){
    
    var obj = object(superType.prototype); 
    obj.constructor=subType; 
    subType.prototype=obj; 
} 
 
function Person(name){
    
    this.name=name; 
} 
Person.prototype.sayName=function(){
    
    console.log(this.name); 
} 
 
function Student(name,age){
    
    Person.call(this,name); 
    this.age=age; 
} 
inheritPrototype(Student,Person); 
var s1 = new Student("jun",30); 
s1.sayName();//jun

这种模式只需要调用一次超类构造函数,是最理想的继承模式。

参考

javascript高级程序设计(第二版)

原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/20294.html

(0)
上一篇 2021年7月19日
下一篇 2021年7月19日

相关推荐

发表回复

登录后才能评论