1. 原型链继承:
// 原型链继承 function Super(){ this.color=['red','yellow','black'] } function Sub(){ } //继承了color属性 Sub.prototype.color=['red','yellow','black'] Sub.prototype=new Super() //创立实例 instance1.__proto__.color const instance1=new Sub() const instance2=new Sub() console.log(instance1.__proto__.color===instance2.__proto__.color) //true
原型链继承问题:
1.实例之间会共享援用类型的值
2.创立子类实例(instance1)时,没有方法向超类型(Super)的构造函数中传递参数
2. 借用构造函数
function Super(name,age){ this.name=name this.age=age this.color=['red','yellow','black'] this.sayHi=function(){ console.log('hi') } console.log(this) } function Sub(){ Super.apply(this,arguments) this.height=180 } //创立实例 var instance1=new Sub('ccdida',25) var instance2=new Sub('piaopiao',25) instance1.sayHi()
Super和Sub中的this都指向instance实例。前者因为Apply扭转了this指向,后者则是因为new操作。
所以每个实例都就有了属于本人的属性,不会相互影响。
构造函数继承问题:
办法只能定义在构造函数中,函数无奈复用
3.组合继承
// 属性 function Super(name,age){ this.name=name this.age=age this.color=['red','yellow','black'] } // 超类办法 Super.prototype.sayHi=function(){ console.log('hi') } function Sub(name,age,height){ //继承属性 Super.apply(this,arguments) this.height=height } // 继承办法(重写子类原型对象) //1.通过原型链继承了办法:Sub.prototype.__proto__===Super.prototype //2.Sub.prototype:{name: undefined, age: undefined, color: Array(3)} //3.Sub原型对象曾经被笼罩,当初只能从原型链上找constructor,指向Super Sub.prototype=new Super() //constructor从新指向Sub Sub.prototype.constructor=Sub console.log(Sub.prototype)//{name: undefined, age: undefined, color: Array(3), constructor: ƒ} // 定义属于子类的办法 Sub.prototype.sayHello=function(){ console.log('sayHello') } //创立实例 var instance1=new Sub('ccdida',25,180) var instance2=new Sub('piaopiao',24,170) console.log(instance1)
console.log(instance1.__proto__===Sub.prototype)//true console.log(instance1.__proto__.__proto__===Super.prototype)//true console.log(Sub.prototype.__proto__===Super.prototype)//true instance1.sayHi() //hi
总结:
1.通过构造函数让实例领有属于本人的属性(name,age,color等),不会相互影响
2.通过原型链继承了父类的办法,实现了函数复用
4.原型式继承
function object(o){ function F(){} //F.prototype={name:'ccdida',friends:['shelly','Bob']} F.prototype=o // new F() //F是个构造函数,返回F的实例:1.this此时用不上 2.将实例的__proto__指向F.prototype. //即返回了一个实例,其__proto__指向{name:'ccdida',friends:['shelly','Bob']} return new F() } var person={ name:'ccdida', friends:['shelly','Bob'] } var person1=object(person) var person2=object(person) //object函数相当于实现了Object.Create的性能 console.log(person1.__proto__===person) //true person2.friends.push('shlimy') console.log(person1.friends)// ["shelly", "Bob", "shlimy"]
毛病:援用类型值会共享
值类型不会共享,因为在扭转值类型时,相当于给本人增加了属性。
当去批改援用类型的某个值时,是在批改__proto__中的对象。但如果间接给援用类型赋值,那也和值类型一样,是给本人减少了属性
person2.friends={} console.log(person1.friends)// ["shelly", "Bob"] person2.name='123' console.log(person1.name)// ccdida
5.寄生式继承
var person={ name:'ccdida', friends:['shelly','Bob'] } function createAnother(original){ //clone.__proto__===original var clone=Object.create(original) //加强对象,增加属于本人的办法 clone.sayHi=function(){ console.log('hi') } return clone } var person1=createAnother(person) var person2=createAnother(person) person1.friends.push('shmily') console.log(person2.friends)//["shelly", "Bob","shmily"] person1.sayHi() //hi
毛病:不能做到函数复用,援用类型数据仍然共享
原型式继承:基于已有的对象(原型对象)创立新对象(实现Object.create())
寄生式继承:创立一个用于封装继承过程的函数(实现Object.create()),同时以某种形式加强对象(比方增加办法)
6.寄生组合式继承
后面的组合继承有个毛病:每次创立实例时都会调用两次超类办法,一次是通过new设置原型的时候,另一次是用apply执行的时候
其实下面打印的时候应该有看到,在通过new继承原型时,执行了构造函数Super,所以Sub.prototype中有name属性
在通过apply执行构造函数时,instance实例上也有了name属性.
所以是不够完满吗?此刻的我还不懂===反正寄生组合式继承能够解决这个问题
所谓寄生组合式继承:通过借用构造函数来继承属性(apply),通过原型链的混成模式来继承办法(Object.create)
思路:不须要为了指定子类型的原型而调用超类型的构造函数(我了解为就是不须要显示的new操作),通过下面的寄生式继承形式来继承超类型的原型即可。
// 寄生组合继承:这个过程既实现了继承,又没有去调用Super function inheritPrototype(Sub,Super){ //subPrototype.__proto__=Super.prototype var subPrototype=Object.create(Super.prototype) //subPrototype.constructor=Sub subPrototype.constructor=Sub //相当于subPrototype有__proto__和constructor两个属性 //即: //Sub.prototype.__proto__===Super.prototype //Sub.prototype.constructor=Sub Sub.prototype=subPrototype } function Super(name){ this.name=name } Super.prototype.sayHi=function(){ console.log(this.name)//ccdida } function Sub(name){ Super.call(this,name) } inheritPrototype(Sub,Super) Sub.prototype.sayHello=function(){ console.log('sayHello') } var instance1=new Sub('ccdida') // instance1.sayHi() console.log(instance1.__proto__) console.log(instance1.__proto__.__proto__)
总结:
实例通过Super.call(this,name)拿到Super中的属性(这些属性属于实例自身,不会被共享)
子类通过Object.create,让子类的原型对象的隐式原型(proto)指向父类的原型对象,实现办法的继承(可复用)
撒花~~~