JavaScript继承

面向对象编程思想:根据需求,分析对象,找出对象有什么特征和行为,通过代码的方式实现需求,要想实现需求,就要创建对象,要想创建对象,就应该先有构造函数,然后通过构造函数来创建对象,通过对象调用相应的属性和方法实现相应的功能和需求。

首先JS不是一门面向对象的语言,JS是一门基于对象的语言,学习JS还要学习面向对象的思想,是因为面向对象的思想适合于人的想法,编程起来更加方便,利于后期的维护…(面向对象编程思想的优点:高内聚,低耦合)

JS中没有类的概念,但是JS可以模拟面向对象编程思想,JS会通过构造函数模拟类的概念(class)

面向对象的三个特性:封装,继承,多态

  • 封装:就是包装
    • 一个值存储在一个变量中===》封装
    • 一堆重复的代码放在一个函数中===》封装
    • 一系列的属性放在一个对象中===》封装
    • 一些功能相似的函数(方法)放在一个对象中===》封装
    • 好多类型的对象放在一个js文件中===》封装
  • 继承:继承指的是一种关系,是类与类之间的关系,JS中没有类的概念,但是JS可以通过构造函数模拟类,然后通过原型来实现继承
    • 原型的作用之一:数据共享,节省内存空间
    • 原型的作用之二:为了实现继承
  • 多态:一个对象有不同的行为,或者同一个行为针对不同的对象有不同的结果。要想有多态就要先有继承,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("睡觉");
};

function Student(score) {
    this.score = score;
}

Student.prototype = new Person("小明", 20, "男"); // ====>改变Student构造函数的 原型的 指向,从而使其 实例对象继承了Person中的属性和方法
var stu = new Student(100);
console.log(stu.name);
stu.eat(); // ==========>能够调用说明从Person中继承了这些属性和方法
stu.sleep();
借用构造函数继承
  • 指的是,继承的时候不改变原型的指向,在子级构造函数里面调用父级的构造函数直接给属性赋值======》父级构造函数名字.call(当前对象this,属性1,属性2,…);
  • 解决了属性继承,并且值不重复的问题
  • 缺点是:只能从父级继承属性,父级类别中的方法没有继承
function Person(name, age, sex) {
    this.name = name;
    this.age = age;
    this.sex = sex;
    this.sayHi = function () {
        console.log("您好");
    };
}

Person.prototype.eat = function () {
    console.log("吃东西了");
};

function Student(name, age, sex, score) {
    //在Student的构造函数内调用了Person的构造函数
    Person.call(this, name, age, sex);//=====》当前学生对象呼叫Person这个构造函数(构造函数是不能直接调用的)
    this.score = score;
}

Student.prototype.study = function () {
    console.log("今天也是开心地学习的一天");
};
var stu = new Student("张三", 20, "男", 200);
console.log(stu.name);//可以调用说明Student从Person中继承了属性
stu.sayHi();//构造函数中的属性(虽然也是方法)实现了继承,但是构造函数通过原型对象添加的方法不会继承
//stu.eat();//======>stu.eat is not a function==》这种方式没有从父级构造函数中继承方法=====》构造函数通过原型对象添加的方法不会继承
stu.study();
组合继承
  • 指的是同时使用通过原型实现继承和借用构造函数实现继承
  • 原型继承能继承方法(改变原型对象指向时new的父级类别的实例对象不传参数),借用构造函数实现继承能解决值重复的问题
function Person(name,age,sex) {
    this.name=name;
    this.age=age;
    this.sex=sex;
    this.sayHi=function () {
      console.log("您好");
    };
}
Person.prototype.eat=function () {
  console.log("吃饭");
};
function Student(name,age,sex,score) {
    Person.call(this,name,age,sex);//当前学生对象呼叫Person方法=======》调用构造函数实现继承
    this.score=score;
}
Student.prototype=new Person();//=================================>改变构造函数原型对象的指向,不传值
Student.prototype.study=function () {
  console.log("今天也是开心得学习的一天");
};
var stu=new Student("小李",30,"女",130);
console.log(stu.name);//=====>能够调用说明从父级类别中继承了这个属性
console.log(stu.age);
console.log(stu.score+"分");
stu.sayHi();//=====>能够调用
stu.eat();//=======>能够调用说明从父级类别的原型对象中继承了方法
stu.study();
拷贝继承
  • 指的是把对象中需要继承的属性或者方法,直接通过遍历的方式复制到另一个对象中
function Person() {

}

Person.prototype.age = 20;
Person.prototype.sex = "男";
Person.prototype.sayHi = function () {
    console.log("您好哇!");
};
var stu = {};
for (var key in Person.prototype) {//遍历父级类别的构造函数的原型对象,复制到需要共享数据的对象当中===>这也算是一种继承,但是事实上并没有实现数据的共享,应为复制过来的属性有自己独立的内存空间
    stu[key] = Person.prototype[key];
}
console.log(stu.age);
console.log(stu.sex);
stu.sayHi();

现在可以做出区分:

原型的作用是数据共享,目的是节省内存空间

原型的作用也是为了继承,目的是节省内存空间

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值