js 继承方式汇总

    技术2025-07-06  20

    一、原型链继承

    将构造函数的原型设置为另一个构造函数的实例对象,这样就可以继承另一个原型对象的所有属性和方法,可以继续往上,最终形成原型链。

    //1、原型链继承, 引用类型的属性(Array,Map,Set,{})会被所有实例共享, 子类实例不能像引用类型构造函数传参 function User(){ this.name = 'py' this.age = 20 this.arr = [1] } User.prototype.show = function(){ console.log(this.name, this.age, this.arr) } function Admin(){} Admin.prototype = new User() let admin1 = new Admin() admin1.arr.push(2) admin1.age = 10 let admin2 = new Admin() admin2.arr.push(3) admin1.show() //py 10 [ 1, 2, 3 ] admin2.show() //py 20 [ 1, 2, 3 ]

    缺点:

    引用类型的属性被所有实例共享。在创建子类型的实例时,没有办法在不影响所有对象实例的情况下给引用类型的构造函数中传递参数。

    二、构造函数继承(经典继承)

    复制父类构造函数内的属性

    //2、构造函数继承, 可以传参数 function User(name, age){ this.name = name this.age = age } User.prototype.show = function(){ console.log(this.name, this.age) } function Admin(name, age){ User.call(this, name, age) } let admin = new Admin('javascript', 25) // admin.show() //TypeError: admin.show is not a function console.log(admin.name, admin.age) //javascript 25

    优点:

    避免了引用类型的属性被所有实例共享可以在子类中向父类传参

    缺点:

    只是子类的实例,不是父类的实例方法都在构造函数中定义,每次创建实例都会创建一遍方法

    三、组合继承(原型链继承 + 构造函数继承)

    使用原型链实现对原型方法的继承,而通过借用构造函数来实现对实例属性的继承。

    //3、组合继承(原型链继承 + 构造继承),同时继承了原型链属性和方法,但调用了两次构造函数 function User(name, age){ this.name = name this.age = age } User.prototype.show = function(){ console.log(this.name, this.age) } function Admin(name, age){ User.call(this, name, age) //第二次调用 } Admin.prototype = new User() //第一次调用 Admin.prototype.constructor = Admin let admin = new Admin('vue', 10) admin.show() console.log(admin instanceof User) //true console.log(admin instanceof Admin) //true

    优点: 融合原型链继承和构造函数的优点,是JavaScript中最常用的继承模式 缺点: 调用了两次父类构造函数(组合继承最大的问题是无论什么情况下,都会调用两次超类型构造函数:一次是在创建子类型原型的时候,另一次是在子类型构造函数内部)

    四、原型式继承

    不自定义类型的情况下,临时创建一个构造函数,借助已有的对象作为临时构造函数的原型,然后在此基础实例化对象,并返回。

    //4、原型式继承, 创建一个临时构造函数,并将构造函数的原型指向需要继承的对象, //缺点: 包含引用类型的属性值始终都会共享相应的值, 这点跟原型链继承一样 let User = {name: 'js', arr:[1]} // 相当于Object.create(obj) function CreateObj(obj){ function F(){} F.prototype = obj return new F() } let user1 = CreateObj(User) user1.name = 'vue' user1.arr.push(2) let user2 = CreateObj(User) user2.name = 'react' user2.arr.push(3) console.log(User.name, User.arr) //js [ 1, 2, 3 ]

    缺点: 包含引用类型的属性值始终都会共享相应的值, 这点跟原型链继承一样

    五、寄生式继承

    其实就是在原型式继承得到对象的基础上,在内部再以某种方式来增强对象,然后返回。

    //5、寄生式继承,创建一个仅用于封装继承过程的函数,该函数在内部以某种形式来做增强对象,最后返回对象。 //可以理解为在原型式继承的基础上新增一些函数或属性. //缺点:跟借用构造函数一样,每次创建对象都会创建一遍方法 let User = {name: 'go', arr:[1]} function admin(User){ const instance = Object.create(User) instance.show = function(){ console.log(this.name, this.arr) } instance.append = function(x){ this.arr.push(x) } return instance } let a1 = admin(User) let a2 = admin(User) a1.append(2) a2.append(3) a1.show() // go [ 1, 2, 3 ] a2.show() // go [ 1, 2, 3 ]

    缺点: 跟借用构造函数一样,每次创建对象都会创建一遍方法

    六、寄生组合式继承

    寄生组合式继承, 即通过借用构造函数来继承属性, 在原型上添加共用的方法, 通过寄生式实现继承.

    //6、寄生组合式继承,子类构造函数复制父类的自身属性和方法,子类原型只接收父类的原型属性和方法 function User(name, age) { this.name = name this.age = age } User.prototype.show = function () { console.log(this.name, this.age) } function admin(name, age){ const instance = Object.create(User.prototype) User.call(instance, name, age) instance.role = function(){ //增强对象 console.log('role') } return instance } let a = admin('jj', 20) a.show() // jj 20 a.role() // role

    只调用了一次父类构造函数,效率更高。避免在 SuberType.prototype上面创建不必要的、多余的属性,与其同时,原型链还能保持不变。 因此寄生组合继承是引用类型最理性的继承范式


    1、面向对象的多态

    function User(){} User.prototype.show = function(){ console.log(this.description()) } function Admin(){} Admin.prototype = Object.create(User.prototype) Admin.prototype.description = function(){ return 'admin' } function Member(){} Member.prototype = Object.create(User.prototype) Member.prototype.description = function(){ return 'menber' } function Enterprise(){} Enterprise.prototype = Object.create(User.prototype) Enterprise.prototype.description = function(){ return 'enterprise' } for (const obj of [new Admin(), new Member(), new Enterprise()]){ obj.show() }

    2、使用原型工厂封装继承

    function User(name, age) { this.name = name this.age = age } User.prototype.show = function () { console.log(this.name, this.age) } //封装一个继承函数 function extend(sub, sup){ sub.prototype = Object.create(sup.prototype) Object.defineProperty(sub.prototype,'constructor',{ value: sub, enumerable: false }) } function Admin(...args){ User.apply(this, args) } extend(Admin, User) let a = new Admin('jj',20) a.show() function Member(...args){ User.apply(this, args) } extend(Member, User) let m = new Member('py',28) m.show()

    3、实现多继承

    function extend(sub, sup){ sub.prototype = Object.create(sup.prototype) Object.defineProperty(sub.prototype, 'constructor',{ value: sub, enumerable: false }) } const Adress = { getAdress(){ console.log('获取用户地址') } } const Request = { ajax(){ console.log('请求后台') } } const Credit = { total(){ console.log('积分统计') } } function User(name, age){ this.name = name, this.age = age } User.prototype.show = function(){ console.log(this.name, this.age) } function Admin(name, age){ User.call(this, name, age) } extend(Admin, User) // Admin.prototype.ajax = Request.ajax // Admin.prototype.total = Credit.total Admin.prototype = Object.assign(Admin.prototype, Credit, Request) let admin = new Admin('jj', 20) admin.show() // jj 20 admin.ajax() // 请求后台 admin.total() // 积分统计

    4、多继承的内部继承与super关键字

    function extend(sub, sup) { sub.prototype = Object.create(sup.prototype) Object.defineProperty(sub.prototype, 'constructor', { value: sub, enumerable: false }) } const Request = { ajax() { return "请求后台" } } const Adress = { __proto___: Request, getAdress() { //super == this.__proto__ console.log(super.ajax() + '获取用户地址') } } const Credit = { total() { console.log('积分统计') } } function User(name, age) { this.name = name, this.age = age } User.prototype.show = function () { console.log(this.name, this.age) } function Admin(name, age) { User.call(this, name, age) } extend(Admin, User) // Admin.prototype.ajax = Request.ajax // Admin.prototype.total = Credit.total Admin.prototype = Object.assign(Admin.prototype, Credit, Adress) let admin = new Admin('jj', 20) admin.show() // admin.ajax() admin.total()

    推荐B站一个up主的视频,讲的非常全面与详细 :传送门

    Processed: 0.010, SQL: 9