原型和原型链

原型

  • 原型的出现,就是为了解决 构造函数的缺点

  • 也就是给我们提供了一个给对象添加函数的方法

  • 不然构造函数只能给对象添加属性,不能合理的添加函数就太 LOW 了

prototype

  • 每一个构造函数天生自带一个成员,叫做 prototype,是一个对象空间

  • 即然每一个函数都有,构造函数也是函数,构造函数也有这个对象空间

  • 这个 prototype 对象空间可以由函数名来访问

    function Person() {}
    
    console.log(Person.prototype) // 是一个对象

    即然是个对象,那么我们就可以向里面放入一些东西

    function Person() {}
    
    Person.prototype.name = 'prototype'
    //向prototype里面添加属性
    Person.prototype.sayHi = function () {}
    //向prototype里面添加方法

  • 我们发现了一个叫做 prototype 的空间是和函数有关联的

  • 并且可以向里面存储一些东西

  • 重点: 在函数的 prototype 里面存储的内容,不是给函数使用的,是给函数的每一个实例化对象使用的

那实例化对象怎么使用能?

__proto__

  • 每一个对象都天生自带一个成员,叫做 __proto__,是一个对象空间

  • 即然每一个对象都有,实例化对象也是对象,那么每一个实例化对象也有这个成员

  • 这个 __proto__ 对象空间是给每一个对象使用的

  • 当你访问一个对象中的成员的时候

    • 如果这个对象自己本身有这个成员,那么就会直接给你结果

    • 如果没有,就会去 __proto__ 这个对象空间里面找,里面有的话就给你结果

  • 那么这个 __proto__ 又指向哪里呢?

    • 这个对象是由哪个构造函数 new 出来的

    • 那么这个对象的 __proto__ 就指向这个构造函数的 prototype

      function Person() {}
      
      var p1 = new Person()
      
      console.log(p1.__proto__ === Person.prototype) // true

    • 我们发现实例化对象的 __proto__ 和所属的构造函数的 prototype 是一个对象空间

    • 我们可以通过构造函数名称来向 prototype 中添加成员

    • 对象在访问的时候自己没有,可以自动去自己的 __proto__ 中查找

    • 那么,我们之前构造函数的缺点就可以解决了

      • 我们可以把函数放在构造函数的 prototype

      • 实例化对象访问的时候,自己没有,就会自动去 __proto__ 中找

      • 那么也可以使用了

        function Person() {}
        
        Person.prototype.sayHi = function () {
          console.log('hello Person')
        }
        
        var p1 = new Person()
        p1.sayHi()

        • p1 自己没有 sayHi 方法,就会去自己的 __proto__ 中查找

        • p1.__proto__ 就是 Person.prototype

        • 我们又向 Person.prototype 中添加了 sayHi 方法

        • 所以 p1.sayHi 就可以执行了

      • 到这里,当我们实例化多个对象的时候,每个对象里面都没有方法

        • 都是去所属的构造函数的 protottype 中查找

        • 那么每一个对象使用的函数,其实都是同一个函数

        • 那么就解决了我们构造函数的缺点

          function Person() {}
          
          Person.prototype.sayHi = function () {
            console.log('hello')
          }
          
          var p1 = new Person()
          var p2 = new Person()
          
          console.log(p1.sayHi === p2.sayHi)

  • p1Person 的一个实例
  • p2Person 的一个实例
  • 也就是说 p1.__proto__p2.__proto__ 指向的都是 Person.prototype
  • p1 去调用 sayHi 方法的时候是去 Person.prototype 中找
  • p2 去调用 sayHi 方法的时候是去 Person.prototype 中找
  • 那么两个实例化对象就是找到的一个方法,也是执行的一个方法
  • 结论

    • 当我们写构造函数的时候

    • 属性我们直接写在构造函数体内

    • 方法我们

原型链

JavaScript 中的每个对象都有一个属性 `__proto__`(非标准属性)指向它的原型对象,该原型对象也有自己的原型,这个原型对象又有自己的原型,如此递归,直到 `null`。这条链路就被称为原型链。

当我们访问一个对象的属性时,如果该对象本身没有这个属性,那么 JavaScript 引擎会沿着对象的原型链依次查找,直到找到该属性或者查找到链的末尾(`null`)为止。

例如,如果我们有一个对象 `obj`,我们使用 `obj.prop` 访问一个属性。如果 `obj` 自身没有这个属性,那么 JavaScript 就会查找 `obj.__proto__` 所指向的原型对象是否有该属性,如果仍然没有,就继续查找 `obj.__proto__.__proto__` 所指向的原型对象,以此类推,直到找到该属性或者查找到链的末端Object.prototype.__proto__。

如果最终没有找到该属性,那么 JavaScript 引擎就会返回 `null`。

原型链的访问原则

  • 我们之前说过,访问一个对象的成员的时候,自己没有就会去 __proto__ 中找

  • 接下来就是,如果 __proto__ 里面没有就再去 __proto__ 里面找

  • 一直找到 Object.prototype 里面都没有,那么就会返回 undefiend

  • Object.prototype.__proto__ 的原型是null

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值