__proto__、Prototype、constructor

prototype

函数的对象的原型,给其它对象提供共享属性,函数所独有的

它的作用是:new对象的时候,告诉新创建的实例他的构造函数是谁,有哪些共享属性和方法

如下所示,t 中并没有 M,但是有 x 和 y,说明 M 没有共享,但是 x 和 y共享了

__proto__

__proto__,隐式原型对象,它是所有对象(包括函数)都有的。

任何一个对象都有 __proto__,它作为一个对象的隐式原型(__proto__)指向构造该对象的构造函数的原型(prototype),这也保证了实例能够访问在构造函数原型中定义的属性和方法。

其实就是 A函数实例__proto__  =>  A函数的prototype,此时就可以访问到 prototype 上存储的共享属性了

这时候有同学就要问了,那我直接通过字面量创建的对象 { } 呢?

其实就是相当于 new Object(),不信你试试 {}.__proto__ === Object.prototype

原型链

当你在访问一个对象属性的时候,如果该对象内部不存在这个属性,那么就回去它的 __proto__ 上查找,如果依旧不存在这个属性,那么就继续沿着 __proto__ 的 __proto__ 查找。以此类推,直到找到 null。而这个查找的过程,也就构成了我们常说的原型链。

这里引出一个点,既然刚才说到,A函数实例的__proto__  =>  A函数的prototype,这里又说到 __proto__ 可以一直往上找,直到null为止

那么替换一下, A函数prototype__proto__是什么呢?(有点绕,其实就是一个替换)

没错,就是其父类的函数(这里我觉的直接说父类好理解)的 prototype

仔细捋顺一下其实结构就清晰了

constructor

constructor属性是一个对象指向该对象的构造函数。对象所独有属性。每一个对象都有其对应的构造函数,本身或者继承而来。

通常obj.constructor === obj.__proto__.constructor

对于构造函数,可以理解为通过 function X() { } 实例化后得到的 x 对象,那么 x 的构造函数就是 

原型继承

__proto__ 与 prototype 与 constructor

function Father(){ this.a =1; }   // Father是函数

let child = new Father()          // child是实例对象        

  

    // child 的 隐式原型对象(__proto__) 指向 构造函数(constructor) Father原型(prototype)

  • child._ proto_ === Father.prototype                     

   // child 的 隐式原型对象 的 隐式原型对象 指向 Object 的原型

  • Father.prototype._ proto_ === Object.prototype 

   // Object 再往上就指向 null 了【原型链顶层】

  • Object.prototype._ proto_ === null                     

 

如上所示,和前面分析的一样

其实 child.constructor 是在 __proto__ 原型中找到的 constructor

child.constructor === Father    // true
child.__proto__.constructor === child.constructor   // true

所以其实是这么一个结构:

子类实例对象

  属性方法

  __proto__ ==> 父类(

    父类属性方法

    constructor: function 子类(){}

    __proto__ ==> 父类的父类(

      父类的父类属性方法

      constructor: function 父类(){}

      __proto__。。。一直套娃,最后套到Object,然后是null

    

  )

下面看一段原型代码

function Foo(name) {
  this.name = name;
}
Foo.prototype.myName = function(){
  return this.name;
}
function Bar(name, label){
  Foo.call(this,name);
  this.label = label;
}
// 创建新的Bar.prototype对象并关联到Foo.prototype
Bar.prototype = Object.create(Foo.prototype);
// Notice!现在没有Foo.prototype.constructor了,因为prototype被整个替换成了{}
Bar.prototype.myLabel = function(){ return this.label; } var a = new Bar('a', 'obj a'); a.myName(); //'a' a.myLabel(); //'obj a'

解决办法

可以使用ES6提供的新方法,这样就不会破坏结构了

// obj:要设置其原型的对象。
// prototype:该对象的新原型(一个对象或 null)。
// return:指定的对象。
Object.setPrototypeOf(obj, prototype)

上述方法中,两个参数均需要传入对象

通常使用如下:

当 Bar 和 Foo 都是函数时,因为我们实际需要共享的是 原型prototype 中的属性和方法,所以通常要传入其 原型 prototype 实现 Bar 对 Foo的继承

Object.setPrototypeOf(Bar.prototype, Foo.prototype)

 

posted @ 2021-11-28 23:59  邢韬  阅读(71)  评论(0编辑  收藏  举报