美文网首页
如何用ES5语法实现继承

如何用ES5语法实现继承

作者: 卡拉咖啦 | 来源:发表于2019-08-21 20:23 被阅读0次

    JS 提供了创建类的语法糖 “class”,以及用与创建子类的关键字 “extends”,那么,问题来了,如果我们不用这些语法糖,我们应该如何实现 JS 中的原型继承呢?

    原型链是个什么链

    这是我们知道的:

    值.proto === 值的构造函数.prototype
    这句话的意思是,每个值都有一个隐藏的 proto 属性绑定它的构造函数的 prototype 属性
    如果是一个数组,那么
    [].proto === Array.prototype
    从这个式子表达了一个数组是如何继承数组的原型属性的,而,进一步,数组作为对象的那一部分是怎么继承下来的呢?
    答案是:
    Array.prototype.proto === Object.prototype

    绑定 Object.prototype 的是 Array 构造函数的 prototype 属性。

    于是,所谓的“原型链”,本质上就是多个 prototype 串起来的链。

    prototype 是个什么东西?

    prototype 这个东西,当我们声明一个函数的时候,这个函数就自带一个 prototype 属性,而对象是没有默认的 prototype 属性的(这也是为什么我们说,对象没法被继承,如果还是想继承,需要用到 Object.setPrototypeOf 属性)

    继承.png

    在没有 class 之前,我们是这么给构造函数写原型属性的:

    fn.prototype.a = function(){}
    

    当我们这么写的时候,实际上就意味着,prototype 是一个对象,

    于是,所谓的“原型链”,更本质上就是串起来的对象。

    proto 与 prototype

    当然,仅仅把对象串起来,并不能自动实现“继承”,在整个继承中的关键,其实是“proto”,也就是说,通过 __proto__ 把连起来的对象串,自带“继承”的特效~

    到了这里,我们不得不严格区分一下 proto 与 prototype

    __proto__怎么看都是 prototype 的缩写,而且 值.__proto__ === 构造函数.prototype 不是说明他们完全等同吗?

    但他们确实不是一回事,比如:
    1.如果我们不主动设置的话,对象并没有 prototype 属性,但是对象天生就有 proto;
    2.我们可以把 __proto__ 理解为有继承的作用,但是 prototype 没有;
    3.也就是说,__proto__ 更偏向于表达“绑定、继承”这些动作,而 prototype 表示,被绑定被继承的那堆东西。

    进而,如何绑定 __proto__ ? JS 不允许我们手动设置 __proto__
    对于我们来说,实现一个有继承效果的 __proto__ 就是使用 new, 别忘了,new 的作用之一就是把新生成的对象 proto 属性绑定原型

    构造函数怎么办?

    说了半天,我们还没有提构造函数,我们可以这么认为,上面说讲的内容就是构建一个对象的内在关系,而构造函数所要做的就是让我们的对象“实体化” —— 它就是用来产生对象的。

    当我们 new 一个构造函数的时候,就会产生一个新的空对象,并把这个对象作为 this 把构造函数执行一遍。

    class A {
      constructor(){
        this.x = 1
        console.log("aaa")
      }
    }
    
    class B extends A {
      constructor() {
        super()
        this.y = 2
        console.log("bbb")
      }
    }
    
    let c = new B
    //→ aaa
    //→ bbb
    
    console.log(c) //→ {x: 1, y: 2}
    

    看上面的代码,我们发现,子类用于创建对象的时候,不仅子构造函数会执行,父类的构造函数也会执行。

    到底我们该怎么做?

    于是,如果我们想实现“继承”,应该如何做?关键点在于:
    1.子构造函数要调用父构造函数;
    2.用 new 实现原型链的继承;

    // B 继承 A
    
    function A (){
      this.a = "a"
    }
    A.prototype.fa = function(){console.log("fa")}
    
    function B(){
      A.apply(this, arguments) // 调用 A 构造函数
      this.b = "b"
    }
    
    let f = function(){}
    f.prototype = A.prototype
    B.prototype = new fn() // 通过 new, B.prototype 就变成了一个有 __proto__ 属性指向 A.prototype 的空对象
    
    B.prototype.fb = function(){console.log("fb")} // 设置其它属性 ……
    
    

    相关文章

      网友评论

          本文标题:如何用ES5语法实现继承

          本文链接:https://www.haomeiwen.com/subject/jefwsctx.html