Skip to the content.

关于原型链

一、从prototype最初始的形态开始
  1. 编写一个最简单的函数,打印其prototype的值
       // 一个最简单的函数
       function BFunc() {
         this.a = 1;
         this.b = '123';
       }
    

    BFunc'sPrototype 如图所示:一个函数最初始的prototype是一个对象,且具有有两个属性:constructor__proto__, constructor的值很明显就是这个函数本身, __proto__的值则为Objectprototype(因为所有对象的最顶层原型都是Object.prototype)。

  2. 通过函数实例化一个对象, 打印他的__proto__属性 BFunc'sOBj__proto__ 如图所示:此对象的__proto__属性很明显指向的就是Bfuncprototype属性, 也就是他的构造函数的 prototype(原型对象)。 也就是说,对于一个对象来说, 其__proto__属性指向的就是他构造函数的prototype

二、通过prototype来实现继承

  1. prototype添加属性
       function Afunc () {
         this.a = 1
         this.b = 2
       }
       Afunc.prototype.c = 3
            
       const obj2 = new Afunc()
    

    AFunc'sOBj__proto__

    如图所示:在Afunc的实例对象obj2上,不能直接看到在prototype上定义的c属性,但是使用obj2.c依然可以访问到c属性, 这是因为当试图访问一个对象的属性时,它不仅仅在该对象上搜寻,还会搜寻该对象的原型,以及该对象的原型的原型,依次层层向上搜索,直到找到一个名字匹配的属性或到达原型链的末尾。

  2. 给对象添加一个已经存在于它原型链上的属性会发生什么? Afunc 如图所示:给obj2添加一个c属性后,它原型上的c属性是依然存在的,也就是说,一个对象原型链上的同名属性是可以并行存在的

  3. prototype上函数的指向问题
       // 在 prototype 上定义一个 使用了 this 的函数
    
       function Afunc () {
         this.a = 1
         this.b = 2
       }
       Afunc.prototype.b = 3
       Afunc.prototype.bfunc = function () {
         console.log(this.b)
       }
            
       const obj3 = new Afunc()
       obj3.bfunc() // 运行结果为2å
    
    

    Afunc

    如图所示:prototype伤的函数中打印this.b的值为2而非3,所以prototype上的函数中this指向的是最终继承prototype的实例化的对象

  4. 直接给prototype赋值会怎样 原型链可能会被打破,即构造函数的prototype对象的原型信息可能会发生丢失。 可以通过Object.create函数创建新的对象,此函数的第一个参数值将会是被创建对象的原型。
  5. class语法 class 仅仅是语法糖,其依然是基于原型来实现继承的

三、总结一下

  1. 一个普通对象没有prototype属性
  2. 任何对象都具有__proto__属性,且__proto__指向的是它的构造函数的prototype
  3. 原型链就是__proto__.__proto__.__proto__......直到__proto__null
  4. [[Prototype]]绝大多数情况下等同于__proto__
  5. Object.create()创建出来的对象没有constructor,但是会指向Object的构造函数
  6. 一个对象的属性会指向原型链上最近的那个