js高程学习之继承

//继承
//ESMAscript由于函数没有签名,不支持接口继承,只支持实现继承,通过原型链。
//所有函数的原型对象都是Ojbect的实例(故在不继承的情况下,自定义类型的实例的原型是Ojbect.prototype),而Ojbect函数的原型对象的原型是null(原型链末端)

*************************************************
// 原型链
//继承的基本思想:利用原型让一个引用类型继承另一个类型的属性和方法,
//具体操作:通过将构造函数的原型对象指向另一个类型的实例,而另一个类型的实例的[[prototype]]又指向该类型的原型对象,依次层层递进形成原型链。
//2、基本模式如下:
//原型链:instance->SubType.prototye->Super.prototype->Object.prototype,这里的->可看作是对象的[[prototype]],而SubType.prototype和Super.prototype通过SubType.prototype = new SuperType()来建立联系,因为SuperType的实例对象的[[prototype]]就是指向SuperType.prototype.
//3、原型和实例的关系
//instance instanceof Ojbect 或者SuperType或者SubType都是true,因为instancof检测的是构造函数的prototype是不是在instance实例的原型链上
//Ojbect或者SuperType或者SubType.prototype.isPrototypeOf(instance)都是true,因为这些构造函数的prototype都在instance实例的原型链上。
//4、子类不能通过字面量重写prototype,这样会破环继承的原型链
//5、子类添加方法或者重写父类方法必须在子类替换原型prototype之后写,否则无效。
//6、原型链实现继承的两个问题:
//6.1子类实例会共享父类构造函数中的属性值,因为是通过将父类的一个实例赋值给子类的原型对象。
//6.2在创建子类时,无法像父类传递参数。所以原型链实现继承的形式基本很少用。
function SuperType(){
     
    this.property = 'super';
}
SuperType.prototype.getSuperValue= function(){
     
    return this.property
}

function SubType(){
     
    this.SubProperty = 'sub'
}
//继承了SuperType
SubType.prototype = new SuperType()
SubType.prototype.getSubValue = function(){
     
    return this.SubProperty;
}
var instance = new SubType()
// alert(instance.getSuperValue())//'super'
console.log(instance)

*************************************************
//借用构造函数
//基本思想:在子类型构造函数内部通过call,apply(绑定this)调用父类型构造函数,并且可以传递参数给父类型。这样每个子类实例拥有自己的从父类构造函数里继承而来的属性。
//问题:如果只单纯使用借用构造函数,那么尽管可以拥有自己的属性,但是在方法又得在构造函数里定义,无法复用。所以一般搭配原型链来组合继承。
function SuperType(name){
     
    this.name = name
    this.colors = ['red','blue','green']
}
function SubType(name){
     
    //继承了SuperType
    SuperType.call(this,name)
}

var instance1 = new SubType('jack')
instance1.colors.push('black')
console.log(instance1.colors)//["red", "blue", "green", "black"]

var instance2 = new SubType('lucy')
console.log(instance2.colors)//["red", "blue", "green"]

*************************************************
//组合继承
//基本思想:原型链实现对原型方法和属性的继承(就是这句SubType.prototype=new SuperType()),借用构造函数实现对实例属性的继承,通过原型定义复用方法,又保证每个实例拥有自己的属性。这是js中最常用的继承模式。此时instanceof和isPrototypeOf也能识别组合继承创建的对象
function SuperType(name){
     
    this.name = name;
    this.colors=["red", "blue", "green"]
}
SuperType.prototype.sayName = function(){
     
    alert(this.name)
}
function SubType(name){
     
    //继承SuperType
    SuperType.call(this,name)

    this.age = age;
}
SuperType.prototype = new SuperType()
SubType.prototype.constructor = SubType;//添加constructor属性。至此完成继承

var instance1 = new SubType("Nicholas", 29);
instance1.colors.push("black");
alert(instance1.colors); //"red,blue,green,black"
instance1.sayName(); //"Nicholas";
instance1.sayAge(); //29

var instance2 = new SubType("Greg", 27);
alert(instance2.colors); //"red,blue,green"
instance2.sayName(); //"Greg";
instance2.sayAge(); //27

***********************************************************
//原型式继承
//用途:只想创建一个与指定对象类似的对象,不用构造函数模式。
//思路:借助原型对象,通过将一个临时构造函数F的原型对象设置为指定对象o,返回一个临时对象的实例,那么o就成为了实例的原型对象了,相当于实例拥有了o的属性,并且能重写o的基本类型值属性,共享o的引用类型值属性。
//es5中新增了Object.create(对象,描述符{name:{value:'greg'}})来代替下面这个函数规范原型式继承
function object(o) {
     
    function F() {
      }
    F.prototype = o
    return new F()
}
var person = {
     
    name: "Nicholas",
    friends: ["Shelby", "Court", "Van"]
};
var anotherPerson = object(person);
anotherPerson.name = "Greg";
anotherPerson.friends.push("Rob");

var yetAnotherPerson = object(person);
yetAnotherPerson.name = "Linda";
yetAnotherPerson.friends.push("Barbie");
alert(person.friends); //"Shelby,Court,Van,Rob,Barbie"

************************************
//寄生式继承
//思路和原型式继承紧密相关(其中调用了原型式继承那个object函数或者Object.create),再在内部对新对象通过某种方式(添加方法和属性等)进行增强,最后返回新对象。
//使用场景:在不考虑自定义类型和构造函数的情况下,只想返回一个增强的类似对象。
function createAnother(original) {
     
    var clone = Object.create(original)
    clone.sayHi = function () {
     
        alert('hi')
    }
    return clone
}
var person = {
     
    name: "Nicholas",
    friends: ["Shelby", "Court", "Van"]
};
var anotherPerson = createAnother(person);
anotherPerson.sayHi(); //"hi"

********************************************
//寄生组合式继承(最完美的继承)
//为了解决最常用的组合继承中父类型构造函数在子类构造函数中和通过new调用赋值给子类的原型对象prototype总共调用了两次,在调用子类构造函数创建对象时会重写先前父类new赋值给子类的prototype的属性。
//解决思路:不必调用父类构造函数指定子类型的原型,利用寄生式继承(其实也是利用了将临时构造函数的prototype指定为父类型,返回临时构造函数的实例,此时不用调用父类构造函数,只需调用临时构造函数)来继承父类型的原型,在将结果指定给子类的原型。一句话:创建父类原型的副本指定给子类原型,提高效率。
// 寄生组合继承的基本模式如下:用这个函数调用去替换组合继承里SubType.prototype = new SuperType()
//将父类原型副本指定给子类原型的函数inheritPrototype
function inheritPrototype(subType,superType){
     
    var prototype = Object.create(superType.prototype)
    console.log(prototype)
    prototype.constructor = subType;
    subType.prototype = prototype
}

//父类
function SuperType(name){
     
    this.name = name;
    this.colors = ['red','blue','green']
}
SuperType.prototype.sayName = function(){
     
    alert(this.name)
}

//子类
function SubType(name,age){
     
    // 继承父类属性
    SuperType.call(this,name)

    this.age = age
}
inheritPrototype(SubType,SuperType)//封装了指定创建的父类原型副本给子类原型,并添加constructor属性的逻辑

SubType.prototype.sayAge = function(){
     
    alert(this.age)
}

var instance = new SubType('nicholas',29)
instance.sayName()//alert('nicolas')
instance.sayAge()//alert(29)

你可能感兴趣的:(JS)