关于js继承中那些不得不说的事,看了后悔一小时,不看后悔60分

继承在js中占有非常重要的地位,那么在js中有很多中继承的方式,不过每一种继承方式都有优缺点。下面就列举几种继承的方式。

1.实现继承首先需要一个父类,在js中实际上是没有类的概念,在es6中class虽然很像类,但实际上只是es5上语法糖而已

1.原型链继承

父类的实例作为子类的原型

javascript 复制代码
javascript
复制代码

function People(name, age) {
   //属性
   this.name = name || '小美'
   this.age = age || 20
   //实例方法
   this.sleep = function () {
       console.log(this.name + '正在睡觉')
   }
}
//原型方法
People.prototype.eat = function (food) {
   console.log(this.name + '正在吃:' + food + ', 今年' + this.age + '岁 ,' + this.sex);
}
// ------------------------ 继承
function Woman() {
}
Woman.prototype = new People('小帅', 18);
let womanObj = new Woman();
womanObj.sex = '男'
womanObj.eat('烧烤') // 小帅正在吃烧烤 今年18岁 男

优点:

简单易于实现,父类的新增的实例与属性子类都能访问

缺点:

可以在子类中增加实例属性,如果要新增加原型属性和方法需要在new 父类构造函数的后面

无法实现多继承

创建子类实例时,不能向父类构造函数中传参数

2.借用构造函数继承(伪造对象、经典继承)

复制父类的实例属性给子类

javascript 复制代码
javascript
复制代码

    function People(name, age) {
            //属性
            this.name = name || '小美'
            this.age = age || 20
            //实例方法
            this.sleep = function () {
                console.log(this.name + '正在睡觉')
            }
        }
        //原型方法
        People.prototype.eat = function (food) {
            console.log(this.name + '正在吃:' + food + ', 今年' + this.age + '岁 ,' + this.sex);
        }
        // ------------------------- 继承
        function Woman(name) {
            //继承了People
            People.call(this, '小帅', 18); //People.call(this,'参数');  可以向父类构造函数中传递参数
        }
        let womanObj = new Woman();
        womanObj.sex = '男'
        womanObj.eat() //报错 无法继承原型方法和属性,只能继承父类的属性和方法
        

优点:

解决了子类构造函数向父类构造函数中传递参数

可以实现多继承(call或者apply多个父类)

缺点:

方法都在构造函数中定义,无法复用

不能继承原型属性/方法,只能继承父类的实例属性和方法

3.实例继承(原型式继承)

javascript 复制代码
javascript
复制代码
function People(name, age) {
    //属性
    this.name = name || '小美'
    this.age = age || 20
    //实例方法
    this.sleep = function () {
        console.log(this.name + '正在睡觉')
    }
}
//原型方法
People.prototype.eat = function (food) {
    console.log(this.name + '正在吃:' + food + ', 今年' + this.age + '岁 ,' + this.sex);
}
// ------------------------- 继承
function Wonman(name) {
    return new People('小帅');
}
let wonmanObj = new Wonman();
wonmanObj.sex = '男'
wonmanObj.eat('烧烤')

优点:

不限制调用方式

简单,易实现

缺点:不能多次继承

4.组合式继承

调用父类构造函数,继承父类的属性,通过将父类实例作为子类原型,实现函数复用

javascript 复制代码
javascript
复制代码

function People(name, age) {
    this.name = name || '小美'
    this.age = age || 20
}
People.prototype.eat = function () {
    return this.name + this.age + '吃 睡'
}
// ------------------------- 继承
function Woman(name, age) {
    People.call(this, name, age)
}
Woman.prototype = new People();
//修复构造函数指向问题
Woman.prototype.constructor = Woman;
let wonmanObj = new Woman('小帅', 27);
console.log(wonmanObj.eat()) // 小帅27吃 睡

缺点:

由于调用了两次父类,所以产生了两份实例

优点:

函数可以复用

不存在引用属性问题

可以继承属性和方法,并且可以继承原型的属性和方法

5.寄生组合继承

通过寄生的方式来修复组合式继承的不足,完美的实现继承

javascript 复制代码
javascript
复制代码
function People(name, age) {
    this.name = name || '小美'
    this.age = age || 20
}
People.prototype.eat = function () {
    return this.name + this.age + '吃 睡'
}
// ------------------------- 继承
function Woman(name, age) {
    //继承父类属性
    People.call(this, name, age)
}
//继承父类方法
(function () {
    // 创建空类
    let Super = function () { };
    Super.prototype = new People();
    //父类的实例作为子类的原型
    Woman.prototype = new Super();
})();
//修复构造函数指向问题
Woman.prototype.constructor = Woman;
let womanObj = new Woman('小帅', 18);
console.log(womanObj.eat()) //小帅18吃 睡

6.es6继承

代码量少,易懂

javascript 复制代码
javascript
复制代码
//class 相当于es5中构造函数
//class中定义方法时,前后不能加function,全部定义在class的protopyte属性中
//class中定义的所有方法是不可枚举的
//class中只能定义方法,不能定义对象,变量等
//class和方法内默认都是严格模式
//es5中constructor为隐式属性
class People {
    constructor(name = '小美', age = 20) {
        this.name = name;
        this.age = age;
    }
    eat() {
        console.log(`${this.name} ${this.age} eat food`)
    }
}
//继承父类
class Woman extends People {
    constructor(name = '小帅', age = 18) {
        //继承父类属性
        super(name, age);
    }
    eat() {
        //继承父类方法
        super.eat()
    }
}
let wonmanObj = new Woman();
wonmanObj.eat();

ES5继承和ES6继承的区别

es5继承首先是在子类中创建自己的this指向,最后将方法添加到this中

Child.prototype=new Parent() || Parent.apply(this) || Parent.call(this)

es6继承是使用关键字先创建父类的实例对象this,最后在子类class中修改this

结束语:

es6中很多代码的语法糖,很多方法简单易用。在浏览器兼容的情况下,改变原有方式。

虽然现在很多框架都是es6,但对于初学者还是建议多看看es5中实现的原理

相关推荐
miss38 分钟前
AI 改完不敢上线?OpenSpec 规约驱动开发实战
前端·代码规范·前端工程化
AiMan1 小时前
腾讯ima还是不可以导出左侧所有对话,只能单条导出,方法不对吗
前端
去伪存真1 小时前
并发量一高就装死?Agent 全链路“防猝死”手册
前端·agent
Moment1 小时前
AI 编程时代,聊聊我的 Mac mini 双屏桌面
前端·后端
AiMan2 小时前
先确认能不能一次把Microsofat Copilot所有内容打包一个文件导出
前端
总要学点什么2 小时前
第97篇:三维数据加载-城市建筑白模自定义着色器——让一条光带沿高度扫上去,快慢却由帧率说了算
前端·gis·webgl·cesium·着色器·空间分析·白模
上海懒图科技2 小时前
工厂厂区电子地图定位导航:厂区人车精准定位,安全合规双保障
前端·arcgis·vue
西安小哥2 小时前
端侧跑大模型,真正的门槛不在参数量:一次 596 秒到 10 秒的压缩路径复盘
前端·人工智能
陈随易3 小时前
Cloudflare 出钱,Vite 团队挑人,44 个维护者分 30 万美元
前端·后端·程序员
恋猫de小郭3 小时前
Flutter THLC 的 WebView 滚动终于从 70 FPS 提升到 120 FPS
android·前端·flutter