原理:将父类的实例作为子类的原型
function Father(){
this.age=10
this.phone={
first:"华为",
second:"小米"
}
}
Father.prototype.getage=function(){
return this.age
}
function Son(name,money){
this.name=name
this.money=money
}
Son.prototype=new Father() //子类型的原型为父类型的一个实例对象
Son.prototype.constructor=Son //让子类型的原型的constructor指向子类型
Son.prototype.getmoney=function(){
return this.money
}
var son=new Son("小米",1000)//
var son2=new Son()
console.log(son.age)//10
console.log(son.getage())//10
console.log(son.name)//小米
console.log(son.getmoney())//1000
console.log(son instanceof Son)//true
console.log(son instanceof Father)//true
son.phone.first="魅族"//更改一个子类的引用属性,其他子类也会受影响
console.log(son2.phone.first)//魅族
优点:1.通过子类实例可以直接访问父类原型链上和实例上的成员
2. 相对简单
缺点:1.创建子类实例时,无法向父类构造函数传参
2.父类的所有引用属性
会被所有子类共享,更改一个子类的引用属性,其他子类也会受影响
原理:在子类构造函数中调用父类构造函数,可以在子类构造函数中使用call()
和apply()
方 法改变this指向
function Father(name,age){
this.name=name
this.age={age:age}
}
Father.prototype.getname=function(){
return this.name
}
function Son(name,age,money){
Father.call(this,name,age)//修改Father的this
this.money=money
}
Son.prototype.getmoney=function(){
return this.money
}
var son=new Son("小明",12,1000)
var son2=new Son("小李",11,999)
console.log(son.name)//小明
console.log(son.getname())//报错 无法继承父类原型上的属性与方法
console.log(son.money)//1000
console.log(son.getmoney())//1000
console.log(son instanceof Father)//false
console.log(son instanceof Son)//true
console.log(son.age.age)//12
console.log(son2.age.age)//11 父类的引用属性不会被共享
优点:1.可以在子类实例中直接向父类构造函数传参
2.父类的引用属性不会被子类共享
缺点:1.无法继承父类原型上的属性与方法
原理:组合上述两种方法就是组合继承。用原型链实现对原型属性和方法的继承,用借用构造函数技术来实现实例属性的继承。
function Father(name,age){
this.name=name
this.age={age:age}
}
Father.prototype.getname=function(){
return this.name
}
function Son(name,age,money){
Father.call(this,name,age)//能够看到父类型属性
this.money=money
}
Son.prototype=new Father()//能看到父元素方法
Son.prototype.constructor=Son//让子类型的原型的constructor指向子类型
Son.prototype.getmoney=function(){
return this.money
}
var son=new Son("小明",12,1000)
var son2=new Son("小李",18,1999)
console.log(son.name)//小明
console.log(son.getname())//小明
console.log(son.money)//1000
console.log(son.getmoney())//1000
console.log(son instanceof Father)//true
console.log(son instanceof Son)//true
console.log(son.age.age)//12
console.log(son2.age.age)//18 父类构造函数中的引用属性不会被共享
优点: 1.可以在子类实例中直接向父类构造函数传参
2. 通过子类实例可以直接访问父类原型链和实例的成员
3.父类构造函数中的引用属性不会被子类共享
缺点:调用了两次supertype构造函数,一次在赋值Son的原型时,一次在实例化子类时call 调用,这次调用会屏蔽原型中的两个同名属性。
原理:利用一个空对象作为中介,将某个对象直接赋值给空对象构造函数的原型。
function object(obj){
function F(){}
F.prototype=obj//对传入其中的对象执行了一次浅复制,将构造函数F的原型直接指向传入的对象。
return new F()
}
var person={
name:"小李",
friends:["小米","小兰"],
sayname:function(){
console.log(this.name)
}
}
var person1=object(person)
person1.name="小王"
person1.friends.push("小黑")
console.log(person1.friends)//['小米', '小兰', '小黑']
person1.sayname()//小王
var person2=object(person)
person2.name="小鱼"
person2.friends.unshift("小葵")
console.log(person2.friends)// ['小葵', '小米', '小兰', '小黑']
person2.sayname()//小鱼
console.log(person.friends)//['小葵', '小米', '小兰', '小黑']
缺点: 1.子类实例不能向父类传参
2.父类的所有引用属性
会被所有子类共享
原理: 在原型式继承的基础上,增强对象,返回构造函数
function object(obj){
function F(){}
F.prototype=obj
return new F()
}
function createAnother(obj){
var clone=object(obj)
clone.getname=function(){ //增强对象
console.log(this.name)
}
return clone
}
var person={
name:"小李",
friends:["小米","小兰"],
}
var person1=createAnother(person)
person1.friends.push("小黑")
person1.name="小红"
console.log(person1.friends)// ['小米', '小兰', '小黑']
person1.getname()//小红
var person2=createAnother(person)
console.log(person2.friends)//['小米', '小兰', '小黑']
person2.getname()//小李
缺点: 1.子类实例不能向父类传参
2.父类的所有引用属性
会被所有子类共享
(同原型式继承)
原理:结合借用构造函数传递参数和寄生模式实现继承
function object(obj){
function F(){}
F.prototype=obj
return new F()
}
function GetPrototype(Father,Son){
var prototype=object(Father.prototype) // 创建对象,创建父类原型的一个副本
prototype.constructor=Son // 增强对象,弥补因重写原型而失去的默认的constructor 属性
Son.prototype=prototype // 指定对象,将新创建的对象赋值给子类的原型
}
function Father(name){
this.name=name
this.color=["blue","pink","black"]
}
Father.prototype.getname=function(){
return this.name
}
function Son(name,age){
Father.call(this,name)
this.age=age
}
GetPrototype(Father,Son) 这一句,替代了组合继承中的Son.prototype = new Father()
Son.prototype.getage=function(){
return this.age
}
var son1=new Son("小米",18)
var son2=new Son()
son1.color.push("green")
console.log(son1.getname()) //小米
console.log(son1.name) //小米
console.log(son1.color) //['blue', 'pink', 'black', 'green']
console.log(son2.color) // ['blue', 'pink', 'black']
console.log(son1 instanceof Father)//true
优点:1. 只调用一次父类构造函数
2. 子类可以向父类传参
3. 父类方法可以复用
4. 父类的引用属性不会被共享
这是最成熟的方法
原理:通过遍历复制前一个对象的属性和方法达到拷贝的效果
function Father(){
this.name="小明",
this.phone={
first:"小米",
second:"华为"
}
}
Father.prototype.getname=function(){
return this.name
}
function Son(name){
var father=new Father()
for(var i in father){
Son.prototype[i]=father[i]
}
}
var son=new Son()
var son2=new Son()
son.phone.first="小李"
console.log(son.name)//小明
console.log(son.getname())//小明
console.log(son2.phone.first)//小李
console.log(son instanceof Father)//false
缺点:1.效率极低,内存占用高(因为要拷贝父类的属性)
2.无法获取父类不可枚举的方法(for in不能访问到的)
3.父类的所有引用属性
会被所有子类共享
class Father {
constructor(name,age){
this.name=name
this.age=age
}
call(){
return "打电话"
}
}
//子类继承父类——语法:class 子类 extends 父类
class Son extends Father{
constructor(name,age,height){
//super在子类的构造方法中调用父类的构造方法
super(name,age) //this操作必须放在super后面
this.height=height
}
play(){
console.log("玩游戏")
}
}
var son= new Son("小王",16,180)
console.log(son.name)//小王
console.log(son.call())//打电话
console.log(son.height)//180
优点:原理还是参照寄生组合继承,基本原理是一样,语法糖,写起来方便,比较完美