JS继承
- 1.JS是面向过程,不是面向对象【面向对象有工厂模式、混合模式......】,js继承是面向对象的一大特征;
- 2.那么面向对象跟面向过程有什么区别呢?
面向过程:
优点:性能比面向对象高,因为类调用时需要实例化,开销比较大,比较消耗资源;比如单片机、嵌入式开发、 Linux/Unix等一般采用面向过程开发,性能是最重要的因素。
缺点:没有面向对象易维护、易复用、易扩展
面向对象:好处之一就是显著的改善了软件系统的可维护性。
优点:易维护、易复用、易扩展,由于面向对象有封装、继承、多态性的特性,可以设计出低耦合的系统,使系统 更加灵活、更加易于维护
缺点:性能比面向过程低
- 3.js继承有三大特征:封装、继承、多态
- 分别简述一下这三大特征:
- ①封装:由于js中是没有类的概念的,我们需要通过new操作符来构建实例,用函数将业务包裹起来;
- ②多态:传参的多少或者不传参会呈现出不同的形态
- ③继承:继承有两大类一类是es5继承,一类是es6继承;
-
一、es5继承: 有五种,常用的有三种
- 1. 原型链继承: 把父类的实例赋值给子类的原型;(父类的实例作为子类的原型)
- 声明父类 People 【首字母大写】
-
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> </body> </html> <script> //声明父类 function People(){ this.name="小明", this.sleep=function(){ console.log(this.name+'会睡觉'); } } //每个函数都有一个prototype属性,别成为显示原型 //将eat方法挂载到原型上 People.prototype.eat=function(){ console.log(this.name+'会吃'); } //声明子类 function Women(){ this.age=18 } //子类继承父类 //把父类的实例赋值给子类原型,就叫做原型链继承 Women.prototype=new People(); let one=new Women() console.log(one.name); one.sleep() one.eat() console.log(one.age) //这个年龄也会打印出来 ---> 18 </script>
上图就是原型链继承,看一下打印的结果
优点:易于实现,父类新增实例与属性子类都能访问
缺点:无法实现多继承,不能向父类传参
- 2.借用构造函数继承: 复制父类实例属性给子类
<script>
//声明父类
function People(){
this.name="小明",
this.sleep=function(){
console.log(this.name+'会睡觉');
}
}
//声明子类 //可以传参
function Women(){
//通过call方法改变this指向
People.call(this) //将父类People中的this.name && this.sleep拿到了Women子类中
}
let one=new Women()
console.log(one.name);
one.sleep()
</script>
根据上图,最终打印的已过
优点:可以向父类传参
缺点:无法继承父类原型上的方法
- 3.组合式继承:结合原型链构造函数继承
调用父类构造函数,继承父类的属性,通过将父类实例作为子类原型,实现函数复用
function People(name, age) {
this.name = name
this.age = age
}
People.prototype.eat = function () {
console.log(this.name + this.age + 'eat sleep')
}
function Woman(name, age) {
People.call(this, name, age)
}
Woman.prototype = new People();
console.log(one.constructor===People) --> 为true
//当修改了this指针
Woman.prototype.constructor = Woman; //修改this指针,将子类原型上的constructor修改为子类实例
console.log(one.constructor===People) --> 为false
let wonmanObj = new Woman("ren", 27);
wonmanObj.eat();
优点:
-
函数可以复用
-
不存在引用属性问题
-
可以继承属性和方法,并且可以继承原型的属性和方法
缺点:由于调用了两次父类,所以产生了两份实例
4.原型继承
用一个函数包装一个对象,然后返回这个函数的调用,这个函数就变成了个可以随意增添属性的实例或对象。object.create()就是这个原理。
特点:类似于复制一个对象,用函数来包装。
缺点:1、所有实例都会继承原型上的属性。
2、无法实现复用。
-
5.寄生组合式继承 (原型式继承外面套了个壳子)
特点:没有创建自定义
-
二、es6继承
-
es6继承⽤class定义类,⽤extends继承类,⽤super()表示⽗类
-
class People{ constructor(name='wang',age='27'){ //可以设置默认值 this.name = name; this.age = age; } //在constructor外面就是定义的原型上的方法 eat(){ console.log(`${this.name} ${this.age} eat food`) } }
声明子类
-
//继承父类 class Woman extends People{ constructor(name = 'ren',age = '27'){ //继承父类属性 super(name, age); } eat(){ //继承父类方法 super.eat() } } let wonmanObj=new Woman('xiaoxiami'); wonmanObj.eat();
-
class son extends father{ }
子类可以没有自己的构造方法,没有可以调用父亲的,但是有构造方法先调用父亲