阅读 39

原型与原型链

       在js中,万事万物皆对象,这些对象都不是独立存在的。他们都是通过一种形式关联起来,这种将所有对象关联起来的东西就叫原型链。除了原始的object对象以外,所有的对象都有他们原型链的上层对象,这个上层对象就是这些对象的原型

  • 在js的代码中,原型链是用__proto__来实现的,所有对象都有自己的__proto__属性,包括最顶层的object对象,他的__proto__属性指向null
  • 我们通过构造函数新建对象,每一个构造函数都有一个prototype属性指向原型,原型也有constructor属性指向这个构造函数。我们可以这样理解,所有不是底层对象的对象都应该有constructor属性,指向创建这个对象的下层对象的构造函数。而构造函数有一个prototype属性表明自己是谁的构造函数,通过我创建的对象的上层对象是谁

  • 不管是__proto__,constructor,还是prototype属性,都是可以被修改的,这就为我们控制原型链提供了可能。
  • 我们通过主动的修改__proto__属性,改变对象的上层对象。但这种方法只是改变一个实例对象的指向,重新new的实例原型指向还是原来的
  • let a=[] let b=[] a.proto=null console.log(a) console.log(b) console.log(a.map) console.log(b.map)

  • 我们先看一组代码

    let b={}
    console.log(b)
    复制代码

通过这个我们可以得知,在js中新创建的所有对象,他的原型链的最上层一定是原始的一个Object对象。

let b=new Array
console.log(b)
复制代码

只要不是由构造函数Object创建的对象,那么他一定是Object创建的对象通过另一构造函数创建的对象。

  • 修改prototype属性,改变原型链指向,直接修改原型链,以后的所有该类的实例原型链指向都被改变

    function Cy(name,age){
            this.name=name
            this.age=age
         }
         function Dw(){
           this.sex='n'
           this.tp=1
         }
    Cy.prototype=new Dw
    Cy.prototype.fun=function(){
             console.log(this.age)
             }
     let a=new Cy('lsq',23)
    console.log(a)
    复制代码

  • 对于constructor属性,有个奇怪的地方(接上方代码)

    let a=new Cy()
    console.log(a.constructor)
    console.log(a.__proto__.constructor)
    复制代码
也就是说,实例的constructor属性指向创建这个实例的构造函数,原型的constructor也指向这个构造函数
  • 每次当我们修改prototype指向的时候,我们往往还要这么做

    Cy.prototype=new Dw
    Cy.prototype.constructor=Cy
    复制代码

这个操作修正了原型constructor指向问题,这样做的理由是

a.constructor.prototype.方法
复制代码

当我们这样添加方法时或许方法会被添加到原来的原型对象上去。

这个地方,我们明明直接a.proto.func,或者Cy.prototype.func添加方法就避开了,我现在是当做习惯去做的,当改变prototype指向时,就修正constructor指向问题。至于这么做的必要性,并不了解。当然也或许是因为__proto__是浏览器提供的属性。。

在这里提一下继承,这样的方式继承就是原型链继承,在子构造函数里用call把父构造函数运行一遍就是构造函数继承,原型链继承方法构造函数继承属性就是组合继承。还有class的继承,直接extends就继承完事了,要注意子类的constructor方法里要super(),调用父类的constructor方法,这与组合式继承岂不异常相似

既然提到了继承,那么创建对象的那么几个方法也就清楚的很了,是的基本就是一一对应不再多说了就。。当然还有寄生,稳妥之类的也就不说了吧。。。


  • 对于constructor属性或许我们能够这么理解,实例对象会继承原型的constructor属性,所以会发现实例的constructor属性与原型的都是指向构造函数,当我们修改prototype属性指向时,constructor指向不修正的话,实例对象继承原型对象的constructor属性,就会发现实例的constructor指向了原型对象原本的constructor指向,很显然这不是我们想要的,所以修正的原因是想让实例继承的constructor属性有正确的指向