原型和原型链的理解(偏面试)

256 阅读3分钟

说说自己的理解

  • 我按照 js 的执行顺序说吧 感觉这样条理 清晰一点

  • 但有一个 前提就是 引用数据类型是存在堆里面的 栈里面存的是指针

  • 首先 函数内部会有一个 Objecrt 构造函数 (注意是构造函数 这个是内置的 也就是不用自己额外定义的)那么构造函数就会有 原型 他的原型 会指向 Object 的原型对象 这个原型对像就是原型链的尽头了 里面会有很多方法 像什么 tostring 什么的 都是在这上面 这个原型对象上面会有一个 隐式原型 _proto 但是这个隐式原型是指向 null 的 所以查找到最后 就是 null 嘛

  • 那么当我们定义一个自己的构造函数的时候 首先还是指针存在栈里面 然后指向一个堆 堆里面是一个构造函数对象 对象有一个显示原型 prototype 然后这个显示原型有一个指针 指向一个 Object 空的实例对象 因为所有对象类型都是基于 Object 的嘛 这个空对象里面就有一个 隐式原型 _proto 这个隐式原型存一个地址 指向 Object 的原型

  • 最后就是实例化对象了 实例化出来的对象 也是一个指针在栈里面 然后指向他的实例对象 那么上面就有一个隐式原型 指向他的构造函数的显示原型上面嘛 然后又因为之前 构造函数的显示原型 也就是之前的 object 空对象 然后他的 隐式原型 会指向 object 的原型嘛 也就是原型链的尽头了

  • 那么查到的时候就是看 本身有没有该属性 没有的话就继续通过隐式原型一直向上 层查找就行了

  • 这里面有一些注意的点

    • 函数得 prototype 属性:是在定义得时候自动添加得 默认值为 null
    • 作用域链查找的时候 跟显示原型没有关系 是通过隐私原型进行查找得
    • 只是在 new 实例化得时候自动添加得 this._proto = Fn.prototype 把原型得地址赋值给了 _proto 才能查找到原型
    • 实例对象的隐式原型指向构造函数的显示原型
  • 另一个 就可以说一下这个函数的原型和原型链的关系

    • new 出来的函数实例 他也是有 隐式原型的

    • 然后所有的函数隐式原型都是一样的 因为都是通过 new Function 得到的

    • function Foo() {} 等效于 var Foo = new Function() 函数对象就是大写 Function 实例

    • 一个很有意思的点 就是构造函数的显示原型和 他的隐式原型指向的是同一个对象

      • 说明什么呢 说明他他是 new 自己创建的

      • 特殊的
        Function = new Function()
        普通的
        var Foo = new Function()
        
      • image.png

    • 不是说那个 函数的显示原型会默认指向一个 空的 Object 实例对象嘛 (但是 Object 是不满足的)

      • 1
    • 所有函数都是 function 的实例(包含 Function )

    • Function._proto === Function.prototype

  • 最后一点 就是 他为什么要这么设计

    • 数据封装

    • 构造函数

      • new this constructor
    • prototype

  • instanceof

    • 左边元素是否为 右边的 实例
    • A(实例对象) instanceof B(构造函数)
    • B 的显示原型对象在 A 对象的隐式原型链上 返回 true
  • 原型链继承

    • 子类的原型 绑定到父类的实例上 就形成了原型链
  • 组合继承

    • 原型链 + 构造函数继承
    • 利用原型链

函数

  • 函数对象是 函数实例
  • function Foo() {} 
    等效于
    var Foo = new Function()
    函数对象就是大写 Function 实例
    ​
    ​
    所以 Foo 其实是函数实例 那么他也有 隐式原型属性
    
  • 所有函数得隐式原型都是一样得 都指向他的显示原型 因为 他都是 通过 new Function 构造得

\