js继承

174 阅读2分钟

js实现继承的方法总结

该篇仅总结了其中三个方法并分析了其优缺点,其余方法可自行学习。

方法一:原型链实现继承

// 原型链实现继承
/**
 * 缺点:
 *  1.包含引用类型值的原型属性会被所有的实例共享。改变了一个实例对象,另一个实例对象也跟着改变,因为s1.__proto__ === s2.__proto__。
 *  2.无法在不影响其它实例的前提下向父类传递参数
 */
function Parent2() {
    this.name = 'parent2';
    this.play = [1, 2, 3];
    this.say = () => {
        console.log('say');
    }
}

Parent2.prototype.age = [];

function Child2() {
    this.type = 'child2';
}
Child2.prototype = new Parent2(); // 所有的实例会共享所有的原型属性(引用类型的),导致修改值的时候出现问题(所有实例上的某属性都被改了
console.log(new Child2().type);
console.log(new Child2().name);
console.log(new Child2().play);

var s1 = new Child2();
var s2 = new Child2();

s1.play.push(4);
console.log(s1.play);
console.log(s2.play);
s1.say();

方法二:构造函数实现继承

// 构造函数实现继承
// * 这种方法的缺点:原型链上的东西没有被继承。
/**
 * 构造函数:一般首字母大写。
 * https://www.jianshu.com/p/7e21e23ffba9
 * ps:
 *  1.首字母大写的函数不一定是构造函数,一个函数是否是构造函数的关键在于有没有被new关键字调用
 *  2.默认返回this,return了复杂类型的数据时就返回return的值,return简单类型还是返回this
 *  3.直接调用构造函数不会报错,使用new的意义在于:this对象指向构造函数生成的对象,new的时候分配的那个新的内存空间
 */
function Parent1() {
    this.name = 'parent1';
}
Parent1.prototype.say = function () { // 原型方法。构造方法不会被继承
    console.log('say');
}
// 原型属性是实例们共享的,若A实例改变了该属性的值,则其它实例的改属性也会被改变。所以:建议将属性封装在构造函数中,将方法定义在原型对象上
Parent1.prototype.family = [1, 2, 3]; // 原型属性(引用类型的属性)。原型属性不会被继承

function Child1() {
    Parent1.call(this);
    this.type = 'child1';
}

console.log(new Child1().name);
console.log(new Child1().say); // undefiend
console.log(new Child1().family); // undefiend

方法三:组合模式

// 组合模式-最常用、最接近ES6的class模式
// 缺点:父类的构造方法执行了2次,分别在Parent3.call(this)和Child3.prototype = new Parent3()。
/**
 * 
 * 优点:
 * 1、创建子类实例,可以向父类构造函数传参数;
 * 2、父类的实例方法定义在父类的原型对象上,可以实现方法复用(原型方法);
 * 3、不共享父类的构造方法及属性(非原型方法及属性);
 */
function Person3(x) {
    this.name = x;
    this.arr = [];
}

Person3.prototype.say = function () {
    console.log('say');
}

function Child3(x) {
    this.nickName = 'child3' + x;
    Person3.call(this, x); // 核心
}

Child3.prototype = new Person3(); // 核心-继承父类的原型方法
// Child3.prototype.constructor = Child3; // 修复子类Child3的构造器指向,防止原型链的混乱

const c1 = new Child3('zhoul');
c1.arr.push(1)
const c2 = new Child3('lan');
console.log(c1.name, c2.name, c1.arr, c2.arr, c1.nickName);
c1.say();
  • 优化父类的构造方法被执行了2次:(寄生组合继承) image.png