1.原型链继承:
<script>
//父类
function Person(){
//实例属性
this.name="张三"
this.sex="男"
this.say=function(){
alert("hi")
}
}
//通过原型给Person添加一个age属性
Person.prototype.age=30
//定义一个子类 来继承我们的Person类
function Student(name){
this.name=name
}
//将父类的实例挂载到子类的原型上
Student.prototype=new Person()
var stu=new Student("晓明")
console.log(Student)
console.log(stu.sex)
//stu.say()
var stu1=new Student("xiaoxiao")
stu1.age=20
stu1.__proto__.age=20
console.log(stu.age)
/*
实现:
将父类的实例挂载到子类的原型上
特点:
实例可继承的属性有:实例的构造函数的属性,父类构造函数属性,父类原型的属性
缺点:
1、新实例无法向父类构造函数传参。
2、继承单一。
3、所有新实例都会共享父类实例的属性。(原型上的属性是共享 的,一个实例修改了原型属性,另一个实例的原型属性也会被修改!)
*/
</script>
2.构造函数继承:
<script>
//父函数
function Person(name){
this.name=name
}
Person.prototype.age=30
//子函数
function Son(sex){
//通过call apply来调用父函数
Person.call(this,"张三")
this.sex=sex
}
var son=new Son("女")
//false
console.log(son instanceof Person)
/*
重点:用.call()和.apply()将父类构造函数引入子类函数(在子类函数中做了父类函数的自执行(复制))
特点:1、只继承了父类构造函数的属性,没有继承父类原型的属性。
2、解决了原型链继承缺点1、2、3。
3、可以继承多个构造函数属性(call多个)。
4、在子实例中可向父实例传参。
缺点:1、只能继承父类构造函数的属性。
2、无法实现构造函数的复用。(每次用每次都要重新调用)
3、每个新实例都有父类构造函数的副本,臃肿。
*/
</script>
3.混合继承(原型链和构造函数混合)
<script>
//父函数
function Person(name){
this.name=name
}
Person.prototype.age=30
//子函数
function Son(name,sex){
//构造函数继承
Person.call(this,name)
this.sex=sex
}
//原型链继承
Son.prototype=new Person()
var son=new Son("小三",'男')
console.log(son.age)
/*
重点:结合了两种模式的优点,传参和复用
特点:1、可以继承父类原型上的属性,可以传参,可复用。
2、每个新实例引入的构造函数属性是私有的。
缺点:调用了两次父类构造函数(耗内存),子类的构造函数会代替 原型上的那个父类构造函数
*/
</script>
4.原型继承
<script>
//父函数
function Person(name){
this.name=name
}
Person.prototype.age=30
//定义一个函数 包装父函数的对象
function wrap(obj){
//定义空函数
var F=function(){};
//将obj挂载到F的原型上
F.prototype=obj
//返回的是F的实例
return new F()
}
//实现继承
var per=new Person("张三")
//调用 wrap
var son=wrap(per)
son.sex="男";
console.log(son)
/*
重点:用一个函数包装一个对象,然后返回这个函数的调用,这个函数就变成了个可以随意增添属性的实例或对象。object.create()就是这个原理。
特点:类似于复制一个对象,用函数来包装。
缺点:1、所有实例都会继承原型上的属性。
2、无法实现复用。(新实例属性都是后面添加的)
*/
</script>
5.寄生式继承
<script>
//父函数
function Person(name){
this.name=name
}
Person.prototype.age=30
//定义一个函数 包装父函数的对象
function wrap(obj){
//定义空函数
var F=function(){};
//将obj挂载到F的原型上
F.prototype=obj
//返回的是F的实例
return new F()
}
//生成一个父的实例
var per=new Person("张三")
//定义一个新的函数,将添加的属性和调用都塞进去
function son(sex){
var sonobj=wrap(per)
sonobj.sex=sex
sonobj.classname='1907A'
return sonobj
}
var son1=son("男")
console.log(son1.name)
/*
重点:就是给原型式继承外面套了个壳子。
优点:没有创建自定义类型,因为只是套了个壳子返回对象(这个),这个函数顺理成章就成了创建的新对象。
缺点:没用到原型,无法复用。
*/
</script>
6.寄生组合式继承:
<script>
function Person(name){
this.name=name
}
Person.prototype.age=30
//定义一个函数 包装父函数的对象
function wrap(obj){
//定义空函数
var F=function(){};
//将obj挂载到F的原型上
F.prototype=obj
//返回的是F的实例
return new F()
}
//调用wrap
var son=wrap(Person.prototype)
console.log(son)
//组合
function Sub(name){
Person.call(this,name)
}
//将包装好的son挂载到Sub的原型上
Sub.prototype=son
var obj=new Sub('xiaosi')
//修复实例
son.constructor=Sub
console.log(obj.age)
</script>
1.原型链继承:
实现: 将父类的实例挂载到子类的原型上
优点: 实例可继承的属性有:实例的构造函数的属性,父类构造函数属性,父类原型的属性
缺点: 1、新实例无法向父类构造函数传参。
2、继承单一。
3、所有新实例都会共享父类实例的属性。
2.构造函数继承:
重点:用.call()和.apply()将父类构造函数引入子类函数
优点:1、只继承了父类构造函数的属性,没有继承父类原型的属性。
2、解决了原型链继承缺点1、2、3。
3、可以继承多个构造函数属性(call多个)。
4、在子实例中可向父实例传参。
缺点:1、只能继承父类构造函数的属性。
2、无法实现构造函数的复用。(每次用每次都要重新调用)
3、每个新实例都有父类构造函数的副本,臃肿。
3.混合继承(原型链和构造函数混合)
重点:结合了两种模式的优点,传参和复用
优点:1、可以继承父类原型上的属性,可以传参,可复用。
2、每个新实例引入的构造函数属性是私有的。
缺点:调用了两次父类构造函数(耗内存),子类的构造函数会代替原型上的那个父类构造函数
4.原型继承
重点:就是给原型式继承外面套了个壳子。 优点:没有创建自定义类型,因为只是套了个壳子返回对象(这个),这个函数顺理成章就成了创建的新对象。 缺点:没用到原型,无法复用。
5.es6的继承:
es6继承⽤class定义类,⽤extends继承类,⽤ super()表示⽗类 class father{ constructor(){} } class son extends father{} 子类可以没有自己的构造方法,没有可以调用父亲的,但是有构造方法先调用父亲