原型链与继承

原型链与继承

原型链

以数组为例,看下面代码

  let arr = [1, 2, 3]
  arr
  /**
    (3) [1, 2, 3]
      0: 1
      1: 2
      2: 3
      length: 3
      [[Prototype]]: Array(0)
      at: ƒ at()
      concat: ƒ concat()
      constructor: ƒ Array()
      copyWithin: ƒ copyWithin()
      entries: ƒ entries()
      every: ƒ every()
      fill: ƒ fill()
      filter: ƒ filter()
      find: ƒ find()
      findIndex: ƒ findIndex()
      flat: ƒ flat()
      flatMap: ƒ flatMap()
      forEach: ƒ forEach()
      includes: ƒ includes()
      indexOf: ƒ indexOf()
      join: ƒ join()
      keys: ƒ keys()
      lastIndexOf: ƒ lastIndexOf()
      length: 0
      map: ƒ map()
      pop: ƒ pop()
      push: ƒ push()
      reduce: ƒ reduce()
      reduceRight: ƒ reduceRight()
      reverse: ƒ reverse()
      shift: ƒ shift()
      slice: ƒ slice()
      some: ƒ some()
      sort: ƒ sort()
      splice: ƒ splice()
      toLocaleString: ƒ toLocaleString()
      toString: ƒ toString()
      unshift: ƒ unshift()
      values: ƒ values()
      Symbol(Symbol.iterator): ƒ values()
      Symbol(Symbol.unscopables): {copyWithin: true, entries: true, fill: true, find: true, findIndex: true, …}
      [[Prototype]]: Object
  */

这个时候我们会奇怪,我们新建的数组中并没有这么多方法。那么这些方法是从何而来的呢。答案是继承

  console.dir(arr.__proto__)
  /**
  [constructor: ƒ, concat: ƒ, copyWithin: ƒ, fill: ƒ, find: ƒ, …]
    at: ƒ at()
    concat: ƒ concat()
    constructor: ƒ Array()
    copyWithin: ƒ copyWithin()
    entries: ƒ entries()
    every: ƒ every()
    fill: ƒ fill()
    filter: ƒ filter()
    find: ƒ find()
    findIndex: ƒ findIndex()
    flat: ƒ flat()
    flatMap: ƒ flatMap()
    forEach: ƒ forEach()
    includes: ƒ includes()
    indexOf: ƒ indexOf()
    join: ƒ join()
    keys: ƒ keys()
    lastIndexOf: ƒ lastIndexOf()
    length: 0
    map: ƒ map()
    pop: ƒ pop()
    push: ƒ push()
    reduce: ƒ reduce()
    reduceRight: ƒ reduceRight()
    reverse: ƒ reverse()
    shift: ƒ shift()
    slice: ƒ slice()
    some: ƒ some()
    sort: ƒ sort()
    splice: ƒ splice()
    toLocaleString: ƒ toLocaleString()
    toString: ƒ toString()
    unshift: ƒ unshift()
    values: ƒ values()
    Symbol(Symbol.iterator): ƒ values()
    Symbol(Symbol.unscopables): {copyWithin: true, entries: true, fill: true, find: true, findIndex: true, …}
    [[Prototype]]: Object
  */

由上我们可以看出多出来的那部分属性其实就是arr.__proto__,尝试以下代码。

  arr.__proto__ === Array.prototype
  // true

  arr.constructor === Array
  // true

每个实例对象(object)都有一个私有属性(称之为 proto )指向它的构造函数的原型对象(prototype)。该原型对象也有一个自己的原型对象(proto),层层向上直到一个对象的原型对象为 null。根据定义,null 没有原型,并作为这个原型链中的最后一个环节。

[[Prototype]] 等同于 __proto__[[Prototype]] 可以通过 Object.getPrototypeOf()Object.setPrototypeOf() 访问器来访问。prototype 是用于类的,而 Object.getPrototypeOf() 是用于实例的(instances

每个实例对象(object)的 constructor 属性都指向它的构造函数。

new的实现

我们执行

  function Person () {
    this.x = 1
    this.y = 2
  }
  let p = new Person();

实际上

  let o = new Object();
  o.__proto__ = Person.prototype;
  Person.call(o);

继承

  • 继承
  // 创建父类
  function Parent () {
    this.x = 1
    this.y = 2
  }
  // 添加原型方法
  Parent.prototype = function run () {}

  // 创建子类并运行父类的构造函数
  function Son () {
    Parent.call(this)
  }
  // 继承父类原型
  Son.prototype = Object.create(Parent.prototype)

  // 修复子类的构造函数为自身
  Son.prototype.constructor = Son

posted @ 2021-11-08 14:34  skylei  阅读(47)  评论(0)    收藏  举报