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)指向父类的原型对象,完成方法的继承(可复用)
撒花~~~
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。