你真的懂原型么?

基本看过高程等书的人都可以对原型继承,原型链查找侃侃而谈,代码中也可以使用原型完成一些事情,但是,我们对于原型真的彻底搞明白了么?

原型由构造器确定

我们的原型是一个对象,构造器函数有一个属性指向这个对象,prototype;而我们每次new出来的实例也有一个属性指向这个对象,__proto__。为什么说原型是由构造器确定的,因为在new之后,这个实例的原型就已经确定了,实例的__proto__和构造器的prototype都会指向那个原型对象。

var Person=function(){};
var p=new Person();
console.log(p.__proto__===Person.prototype);  // true
Person.prototype={
   say:function(){
        console.log("hello");
   }
}
var t=new Person();
console.log(t.__proto__===Person.prototype);  // true
t.say();   // hello

console.log(p.__proto__===Person.prototype);  //  false
p.say();  // 报错

这段代码就很好的说明了这个问题。实例p通过构造器函数Person创建出来(new)之后,它的__proto__和Person的prototype指向同一个对象,所以console的时候相等。然后,我们改变一下构造器函数Person的原型指向,并创建了一个实例t,我们发现t的__proto__和Person的prototype的指向依旧是一致的,但是因为Person.prototype已经改变了,而p.__proto__依旧指向原来的原型对象,所以p.__proto__和现在的Person.prototype指向的对象并不是同一个,会返回false。证据就是p.say()会报错,但是t.say()可以返回正确的值。

原型链查找,是通过实例的属性

看下面的代码:

var Person=function(){};
var p=new Person();
Person.prototype.say=function(){
   console.log("1");
}
p.say();  //1

我们先创建了实例,再给原型添加方法,最后调用时,依旧可以返回正确结果,这说明p.say()是一个查找的过程,它会去原型对象里查找相应的方法,如果有返回结果,没有就会报错。

那么,既然是通过实例调用的方法,自然也是通过实例的__proto__属性去访问到那个原型对象,如何证明?我们看下面的代码:

var Person=function(){};
var p=new Person();
Person.prototype.say=function(){
   console.log(1);
}
p.say();  //1
p.__proto__={
  say:function(){
     console.log(2);
  }
}
p.say();   //2

当我们重写p.__proto__之后,相当于p这个实例的原型就是我们重写的这个对象。无论我们对Person.prototype添加任何方法,p这个实例都访问不到这些方法,因为原型链查找通过的是__proto__属性,而现在,p.__proto__和Person.prototype指向的其实是不同的两个对象了。

原型是客观存在的

当我们new了一个实例之后,原型对象就已经存在了,实例的__proto__和构造器的prototype都会指向它。而创建实例之后,我们如果修改了__proto__或者prototype,其实都是在修改那个唯一的原型对象。要是我们重写了__proto__或者prototype,原型对象依旧存在,但是通过__proto__或者prototype只能访问到重写的那个对象。所以我们一直在强调,new是一个分界线,new的过程就是把实例的__proto__指向构造器的prototype所指向的那个对象。

看点例子:

 

var Person=function(){};
var p=new Person();
var t=new Person();

p.__proto__.say=function(){
   console.log(1);
}
p.say();  //1
t.say();  //1

p.__proto__={ say:function(){ console.log(2); } } p.say(); //2 t.say(); //1 Person.prototype={ say:function(){ console.log(3); } } var x=new Person(); p.say(); //2 t.say(); //1 x.say(); //3

 

如果你对上述代码没有任何疑问,那么,你应该是真的懂了原型。

posted @ 2016-12-07 18:17  出世Sunny  阅读(726)  评论(0编辑  收藏  举报