类与继承

类的声明

原生方法:

function Animal(name){
    this.name = name;
}

ES6方法:

class Animal{
    constructor(name){
        this.name = name;
    }
}

类与继承

实现继承的原理就是原型链。

继承的几种方式

第一种:借助构造函数实现继承

function Parent(name){
    this.name = name;
}

function Child(age,name){
    //在子类构造函数内执行父级构造函数
    //call方法在这里改变了Parent函数运行时的上下文,这样在实例化子类时会将父类中的属性和方法挂载到子类实例上
    Parent.call(this,name);
    //为子类添加自己的属性
    this.age = age;
}
console.log(new Child(18,'happychen'));

在这里插入图片描述
借助构造函数实现继承的缺点:
Parent.call(this) 只是改变了子类实例中的上下文,因此只能继承父级构造函数体内的内容,而Parent.prototype上的内容无法继承。比如:Parent.prototype.say = function(){...} 原型链上的say()方法Child子类是无法继承下来的。

第二种:借助原型链实现继承

先区分三个:

function Parent(name){
    this.name = name;
}
Parent.prototype.say = function(){};
function Child(age){
    this.age = age;
}

Child.prototype = new Parent();
console.log(Parent);
console.log(Parent.prototype);
console.log(new Parent());

在这里插入图片描述
继续:

function Parent(name){
    this.name = name;
}
Parent.prototype.say = function(){};
function Child(age){
    this.age = age;
}

//prototype是子类构造函数的属性,当然,每个函数都有prototype属性,这个属性是可以赋值的,这里赋值为Parent的实例对象,
//new Parent()其实就是一个对象,现在变成了子类prototype的值
Child.prototype = new Parent();
//原型链中介绍过,new Child(18).__proto__ === Child.prototype;
//所以在这里new Child(18).__proto__ 实际上引用的是父类的实例对象
//接着就是按照原型链的查找方式
console.log(new Child(18));

在这里插入图片描述
借助原型链实现继承的缺点:

function Parent(name){
    this.name = name;
    this.nums = [1,2,3];//新增一个引用类型的属性
}
Parent.prototype.say = function(){};
function Child(age){
    this.age = age;
}

Child.prototype = new Parent();

var child1 = new Child();
var child2 = new Child();
console.log(child1.nums,child2.nums);
child2.nums.push(4);
console.log(child1.nums,child2.nums);

在这里插入图片描述
因为原型链中的原型对象是公用的,child1.__proto__ === child2.__proto__引用的是同一个对象,也就是父类的实例对象,而nums在父类实例对象上并且是引用类型,所以child1.nums,child2.nums会相互影响。
在这里插入图片描述
第三种:组合方式(把以上两种方式结合,弥补互相的不足)

function Parent(name){
    this.name = name;
    this.nums = [1,2,3];
}

function Child(age,name){
    Parent.call(this,name);//父类会执行
    this.age = age;
}

Child.prototype = new Parent();//父类会执行

child1 = new Child(18,'happychen');
child2 = new Child(18,'kedaya');
child1.nums.push(4);
console.log(child1);
console.log(child2);

在这里插入图片描述
虽然组合方式比较通用,但也有缺点:
在子类实例化对象时,父类会执行两次(子类函数体内执行了一次,在原型继承时又执行了一次)。然而这两次没必要。

优化继承方法:

function Parent(name){
    this.name = name;
    this.nums = [1,2,3];
}

function Child(age,name){
    Parent.call(this,name);//父类会执行
    this.age = age;
}

// Child.prototype = new Parent();
Child.prototype = Parent.prototype;//此时子类的原型对象和父类的原型对象引用的是同一个对象,而且会改变子类的constructor

child1 = new Child(18,'happychen');
child2 = new Child(18,'kedaya');
child1.nums.push(4);
console.log(child1.constructor);

这种方法也有一个缺点:
在这里插入图片描述
继续优化继承方法:
Object.create(参数)方法创建的对象的原型对象就是它里面的参数。

function Parent(name){
    this.name = name;
    this.nums = [1,2,3];
}

function Child(age,name){
    Parent.call(this,name);//父类会执行
    this.age = age;
}

// Child.prototype = new Parent();
// Child.prototype = Parent.prototype;
Child.prototype = Object.create(Parent.prototype);//这样可以将父类和子类的原型对象隔离

child1 = new Child(18,'happychen');
child2 = new Child(18,'kedaya');
child1.nums.push(4);
console.log(child1.constructor);
console.log(child1.nums,child2.nums);

在这里插入图片描述
Child实例的原型对象是Child.prototype,Child.prototype又是Object.create(参数)的参数。

但是Child的constructor还是Parent,这是手动修改:

function Parent(name){
    this.name = name;
    this.nums = [1,2,3];
}

function Child(age,name){
    Parent.call(this,name);//父类会执行
    this.age = age;
}

// Child.prototype = new Parent();
// Child.prototype = Parent.prototype;
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child // 手动修改Child的constructor

child1 = new Child(18,'happychen');
child2 = new Child(18,'kedaya');
child1.nums.push(4);
console.log(child1.constructor);
console.log(child1.nums,child2.nums);

以上一步一步弄清楚了类继承的原理和区别。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值