通过原型链理解继承

115 阅读3分钟

原型的作用是什么?

function Person(name,age){
    this.name = name ;
    this.age = age;
    this.say = function(){
        console.log('hello');
    };
}

for(var i = 0 ; i<100 i++){
    var per = new Person('张三',25);
    console.log(per.name);
    console.log(per.age);
    per.say();
}

如果想要创建多个对象,并且它们每个属性的值都是一样的,方法也一样,用以上这中方法或许太过繁琐。

function Person(){}
Person.prototype.name = '张三';
Person.prototype.age = 25;
Person.prototype.sayHello=function(){
    console.log('hello');
}
var per = new Person();
console.log(per);
console.log(per.age);
console.log(per.name);
console.log(per.sayHello);

为了共享数据,节省内存空间,我们可以通过以上这种原型的方式进行赋值。

原型链

通过查看结构发现:实例对象的原型__proto__和构造函数的原型prototype指向相同。

原型链:是一种关系,实例对象和原型对象之间的关系,这种关系是通过原型__proto__来联系的。

function Person(){}
//为Person添加原型方法eat
Person.prototype.eat=function(){
    console.log("eat food");
}
function Student(){}
//为Student添加原型方法sayHi
Student.prototype.sayHi=function(){
    console.log("hi");
}
//让学生的原型指向了人的实例对象
Student.prototype=new Person();
var stu =new Student();
// stu.sayHi();  //找不到sayHi方法了
stu.eat();

通过以上了解到:原型指向可以改变

实例对象的原型__proto__指向的是该对象所在的构造函数的原型对象

构造函数的原型对象(prototype)指向如果改变了,实例对象的原型(proto)指向也会改变

prototype也是对象,这个对象中的__proto__指向object这个构造函数的原型对象prototype

object构造函数中的原型对象prototype的__proto__是null

js中通过原型来实现继承

function Person(name,age,sex){
    this.name=name;
    this.age=age;
    this.sex=sex;
}
Person.prototype.eat=function(){
    console.log("吃东西");
};
Person.prototype.sleep=function(){
    console.log("睡觉");
};
Person.prototype.play=function(){
    console.log("玩");
};


function Student(score){
    this.score=score;
}
//改变学生的原型指向即可,但是这里给对象初始化值了
Student.prototype=new Person("ss",10,"男");
// Student.prototype.name='xxx' 可以像这样修改属性值
Student.prototype.study=function(){
    console.log("学习");
};

var stu=new Student(100);

console.log(stu.name); //ss
console.log(stu.age); //10
console.log(stu.sex); //男
console.log(stu.score); //100
stu.eat();
stu.sleep();
stu.play();
stu.study();

为了数据共享,改变原型指向,做到了继承---通过改变原型指向实现的继承

缺陷:因为改变原型指向的同时实现继承,直接初始化了属性,继承来的属性值都一样

function Person(name,age,sex,weight){
    this.name=name;
    this.age=age;
    this.sex=sex;
    this.weight=weight;
}
Person.prototype.sayHi=function(){
    console.log("hello");
};
function Student(name,age,sex,weight,score){
    //借用构造函数
    Person.call(this,name,age,sex,weight);
    this.score=score;
}

var stu1=new Student("小明",20,"男","60kg",100);
console.log(stu1.name,stu1.age,stu1.sex,stu1.weight,stu1.score);
var stu2=new Student("小白",19,"女","50kg",130);
stu1.sayHi();  //报错 父级中的方法不能通过此方式继承

解决方案:继承的时候,不用改变原型的指向,直接调用父级的构造函数的方式来为属性赋值

借用构造函数:构造函数名字.call(当前对象,属性,属性...)

解决了属性继承,并且值不重复的问题

缺陷:父级类别中的方法不能继承

组合继承

组合继承:原型实现继承+借用构造函数继承

function Person(name,age,sex){
    this.name=name;
    this.age=age;
    this.sex=sex;
}
Person.prototype.sayHi=function(){
    console.log("hi");
}

function Student(name,age,sex,score){
    //借用了构造函数,解决了属性值重复问题
    Person.call(this,name,age,sex)
    this.score=score
}
//改变了原型指向,并在原型中添加了eat方法
Student.prototype=new Person();//不传值
Student.prototype.eat=function(){
    console.log("eat");
}
var stu1=new Student("ss",20,"男",100);
console.log(stu1.name,stu1.age,stu1.sex,stu1.score);
stu1.sayHi();
stu1.eat();
var stu2=new Student("xx",25,"男",100);
console.log(stu2.name,stu2.age,stu2.sex,stu2.score);
stu2.sayHi();
stu2.eat();
//属性和方法都被继承了

拷贝继承

拷贝继承:把一个对象中的属性或者方法直接复制到另一个对象中

function Person(){}
Person.prototype.age=20;
Person.prototype.sex="男";
Person.prototype.height=180;
Person.prototype.play=function(){
    console.log("play");
};

var obj2={};

for(var key in Person.prototype){
    obj2[key]=Person.prototype[key];
}
console.log(obj2);

//Person的构造函数中有原型prototype,
//prototype是一个对象,把这个对象里的属性或者方法
//都循环遍历给了obj2