JavaScript 中的继承方式

1. 属性拷贝继承

//创建父级对象
var parent = {
    name: 'xiaoming',
    age: '40',
    sex: 'male',
    showName: function(){
        console.log(this.name);
    }
}

//创建子级对象
var child = {};

//通过遍历将父级对象的属性和方法赋值给子级对象
for(var i in parent){
    child[i] = parent[i];
}

console.log(child);

存在问题:

如果继承的是引用类型的属性时,父级对象与子级对象的属性是共享的,无论谁修改属性,父子对象都会受到影响

2. 原型式继承

原型式继承是借用构造函数的原型对象实现继承,即

子构造函数 . prototype = 父构造函数 . prototype

// 创建父级函数
function Parent (name){
    this.name = name;
    this.showName = function(){
        console.log(this.name);
    }
}

// 设置父级函数的原型对象
Parent.prototype.age = 18;
Parent.prototype.friends = [ '小明', '小红' ];
Parent.prototype.showAge = function(){
    console.log(this.age);
}

// 创建子级函数
function Child (){
    
}

// 通过原型继承父级函数的属性
Child.prototype = Parent.prototype;
var child = new Child();

child.age  // 18
child.friends // [ '小明', '小红' ]
child.showName // undefined

这样一来 child 就继承了 Parent 原型对象上的属性,但仍存在以下问题:

  • 父级构造函数的原型对象和子级构造函数的原型对象存在共享问题,不能随便改动自己的原型,否则双方都会受到影响
  • 只能继承父构造函数的原型对象上的成员, 不能继承父构造函数的实例对象的属性和方法

 

3. 原型链式继承


子类可以继承父类构造函数原型对象和实例上的属性和方法

子构造函数.prototype = new 父构造函数()

// 创建父级构造函数
function Parent(){
    this.name = '小明';
    this.showName = function (){
        console.log(this.name);
    }
}
// 设置父级函数的原型对象
Parent.prototype.age = 18;
Parent.prototype.showAge = function(){
    console.log(this.age);
}

// 创建子级构造函数
function Child (){

}


Child.prototype = new Parent();
Child.prototype.constructor = Child;
var child = new Child();

child.name // '小明'
child.age  // 18
child.showAge()  // 18 

存在问题:

  • 继承了太多没用的属性
  • 不能给父级构造函数传递参数
  • 父子构造函数的原型对象仍然存在共享问题

 

4. 借用构造函数实现继承


使用 callapply 借用构造函数,可以解决给父类构造函数传参的问题

// 创建父级构造函数
function Parent (name, sex, age){
    this.name = name;
    this.sex = sex;
    this.age = age;
}
Parent.prototype.showAge = function(){
    console.log(this.age);
}

// 创建子级构造函数
function Child (name, sex, age){
    //使用 call 借用 Parent 构造函数
    Parent.call(this, name, sex, age);
}

var child = new Child('小明', 'male', 18);

child.name // '小明'
child.age // 18
child.showAge() //报错

存在问题:

  • 不能调用构造函数原型对象的属性和方法
  • 增加了函数的调用

 

5. 组合继承(借用构造函数+原型式继承)


解决了第4种方法中子类同时继承父类构造函数原型对象和实例上的属性和方法问题

// 创建父级构造函数
function Parent (name, sex, age){
    this.name = name;
    this.sex = sex;
    this.age = age;
}
Parent.prototype.showAge = function(){
    console.log(this.age);
}

// 创建子级构造函数
function Child (name, sex, age){
    //使用 call 借用 Parent 构造函数
    Parent.call(this, name, sex, age);
}

// 通过原型继承父级函数的属性
Child.prototype = Parent.prototype;
Child.prototype.constructor = Child;

var child = new Child('小明', 'male', 18);

child.name // '小明'
child.age // 18
child.showAge() // 18

存在问题:

  • 父子构造函数的原型对象仍然存在共享问题

 

6. 圣杯模式


解决了父子构造函数之间的共享问题,同时子级能够继承父级原型和实例的所有属性,并且可以传参

// 创建父级构造函数
function Parent (name, sex, age){
    this.name = name;
    this.sex = sex;
    this.age = age;
}
Parent.prototype.showAge = function(){
    console.log(this.age);
}

// 创建一个空函数
function F(){

}

// 创建子级构造函数
function Child(){

}

// 用空函数 F 的原型对象继承父级构造函数的原型对象,再让 Child 的原型对象继承 F 的实例
F.prototype = Parent.prototype;
Child.prototype = new F();
Child.prototype.constructor = Child;

// 手动设置 uber 属性,表明 Child 最终继承自 Parent
Child.prototype.uber = Parent.prototype;

var child = new Child('小明', 'male', 18);

child.name // '小明'
child.age // 18
child.showAge() // 18

以上代码可以封装为一个继承函数方法

function extend(Target, Origin){
    function F(){};
    F.prototype = Origin.prototype;
    Target.prototype = new F();
    Target.prototype.constructor = Target;
    Target.prototype.uber = Origin.prototype;
}

以上便是JS中实现继承的几种方法,运用的时候需结合实际情况,选择最适合的方法即可

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值