JS面向对象 继承的几种方式

370 阅读1分钟

这是我参与8月更文挑战的第29天,活动详情查看:8月更文挑战

这篇文章主要介绍了JS实现面向对象继承的5种方式,结合实例形式分析了JavaScript面向对象继承功能的5种常见实现方法原理与操作技巧,需要的朋友可以参考下:

 1. 借助构造函数实现继承

function Parent1() {
    this.name = 'Parent1';
}

Parent1.prototype.say = function() {
    console.log('你好');
}

function Child1() {
    Parent1.call(this); // !!!关键点 apply也可以
    this.type = 'child1';
}

let s1 = new Child1();

console.log(s1);
s1.say(); // 此处会报错

关键是 Parent1.call() 这一句,是通过call(apply)改变函数运行上下文,将Parent1的this挂载到Child1的实例上

缺点1:Parent1原型链上边的属性方法等不会被继承。

2.借助原型链继承

function Parent2() {
    this.name = 'parent2';
    this.arr = [1,2,3];
}

function Child2() {
    this.name = 'child2'
}

Child2.prototype = new Parent2(); // 此处为关键

let s2 = new Child2();
let s3 = new Child2();
console.log(s2.arr, s3.arr) // [1,2,3] [1,2,3]

如上,关键在于将Child2的原型指向Parent2的实例

缺点1:这样构造的Child2的实例,都是同一个原型,改变其中一个,其他的实例也会改变

如,接上边,再增加一句

s2.arr.push(4);
console.log(s2.arr, s3.arr); //[1,2,3,4] [1,2,3,4] 

可见,修改s2的arr属性,s3实例也跟着变化

3.组合继承 (解决上边缺点1、2)

// 组合继承
function Parent3() {
    this.name = 'parent3';
    this.arr = [1,2,3];
}

function Child3() {
    Parent3.call(this);
    this.name = 'child3'
}

Child3.prototype = new Parent3();

let s4 = new Child3();
let s5 = new Child3();
s4.arr.push(4)
console.log(s4.arr, s5.arr) // [1,2,3,4] [1,2,3]

缺点3: Child3每次实例化,都要执行Parent3 构造函数,

4.组合继承的优化1

function Parent4() {
    this.name = 'parent4';
    this.arr = [1,2,3];
}

function Child4() {
    Parent4.call(this);
    this.name = 'child4'
}

Child4.prototype = Parent4.prototype; // !!!此处为关键

let s6 = new Child4();
let s7 = new Child4();
s6.arr.push(4)
console.log(s6.arr, s7.arr)

缺点4: 无法区分实例是由Child4还是Parent4直接实例化而来

console.log(s6 instanceof Child4, s6 instanceof Parent4); // 可以发现此时均为 true
console.log(s6.constructor, s7.constructor); // 均为Parent4

5.组合继承2

function Parent5() {
    this.name = 'parent5';
    this.arr = [1,2,3];
}

function Child5() {
    Parent5.call(this);
    this.name = 'child5'
}

Child5.prototype = Object.create(Parent5.prototype); //  !! 此处为关键

let s8 = new Child5();
let s9 = new Parent5();

console.log(s8 instanceof Child5, s9 instanceof Child5); // true, false
console.log(s8.constructor, s9.constructor); // 均为Parent5

关键在于,通过 Object.create 构造一个中间对象,用以区分

缺点:两者 constructor 还是全部指向 Parent5

可通过如下手动设置,解决

Child5.prototype.constructor = Child5;