你知道JavaScript的继承有几种写法吗?

标题的灵感来源于鲁迅的小说《孔乙己》中孔乙己和小伙计的一段对话:“茴香豆的茴字,怎样写的?……回字有四样写法,你知道么?”

这里我们并不探讨封建制度下穷苦潦倒的读书人的迂腐,回字的几种写法留给汉语言的同学去研究吧,今天我们讨论JavaScript继承的几种写法,由浅入深,一层层剥开她的面纱,最后给出一个最佳实践。

一、通过构造函数实现继承

    function Parent() {
      this.name = 'name';
    }
    Parent.prototype.say = function () {
      console.log('say');
    }
    function Child() {
      Parent.call(this);
      this.type = 'child';
    }
    const child = new Child();

这种方式通过在子类的构造函数中调用父构造函数实现继承,但是有个致命的缺点:如下图,子类实例并不能继承父类中原型对象上的属性或者方法。

这里写图片描述

二、通过原型对象实现继承

    function Parent() {
      this.name = 'name';
      this.favor = ['blue', 'red'];
    }
    Parent.prototype.say = function () {
      console.log('say');
    }
    function Child() {
      this.type = 'child';
    }
    Child.prototype = new Parent();
    const child = new Child();

这种方式通过给子类构造函数的prototype对象赋值实现继承,如下图,无论是name属性还是say方法都能被子类实例访问到。
这里写图片描述
但是这种方式也有缺点,如下图,当父类的属性是引用类型时,子类实例继承的是同一份属性,任一实例改变该属性都会引起全局变化,无法互相隔离。
这里写图片描述

三、组合方式

    function Parent() {
      this.name = 'name';
      this.favor = ['blue', 'red'];
    }
    Parent.prototype.say = function () {
      console.log('say');
    }
    function Child() {
      Parent.call(this);
      this.type = 'child';
    }
    Child.prototype = new Parent();
    const child = new Child();

结合了上两种方式,避免了上面的缺点。但是这种方式在每次实例化子类实例时,都会调用两次父类构造函数,需要优化。

四、组合优化①

    function Parent() {
      this.name = 'name';
      this.favor = ['blue', 'red'];
    }
    Parent.prototype.say = function () {
      console.log('say');
    }
    function Child() {
      Parent.call(this);
      this.type = 'child';
    }
    Child.prototype = Parent.prototype;
    const child = new Child();

在给子类prototype赋值时不要采用实例化父类的方式,直接赋值父类的prototype

其实,这种方式也有缺点:如下图,子类实例的constructor属性直接指向了父类构造函数,导致无法判断当前对象实例化自哪个构造函数。

这里写图片描述

五、组合优化②

    function Parent() {
      this.name = 'name';
      this.favor = ['blue', 'red'];
    }
    Parent.prototype.say = function () {
      console.log('say');
    }
    function Child() {
      Parent.call(this);
      this.type = 'child';
    }
    Child.prototype = Object.create(Parent.prototype);
    Child.prototype.constructor = Child;
    const child = new Child();

终极改造完成:通过Object.create()方法指定了子类实例的__proto__属性,同时显式声明子类的constructor

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值