浅谈原型对象和原型链

上一篇随笔有提到过原型链的问题,这次就讲一下原型链。

讲原型链之前要先说一下什么是原型对象。

原型对象:原型对象是新对象的模板,它将自身的属性通过this共享给新对象。一个对象不但可以享有自己创建时和运行时定义的属性,而且可以享有原型对象的属性。

也可以简单理解成原型对象就是父类,新的对象就是继承了父类的属性和方法的子类,但这种理解又略显片面

1 function a(){
2     this.b=b;
3     this.c=function(){alert("hi")};
4 }
5 
6 var R = new a();         //这里的a就是原型对象,R继承了a的属性和方法

 

现在再来说一下原型链,在每个函数对象创建的时候,都会自带一个prototype的属性,这个属性相当于一个指针,指向他本身的原型对象,这个原型对象里包含着自定义的方法属性。

举个例子:实例(_proto)→原型对象(constructor)→构造函数

  • prototype:构造函数中的属性,指向该构造函数的原型对象。

  • constructor:原型对象中的属性,指向该原型对象的构造函数

  • _proto_:实例中的属性,指向new这个实例的构造函数的原型对象

可能看到这里,对构造函数的原型对象又有点迷惑了,上面讲到a就是原型对象,但是a同时也是构造器。

再补充一点:原型对象就是一种特殊的对象,构造函数创建时自动生成;与构造函数形成一一对应,如同人和影子般的关系。

过程如下:

1 var temp = new f1();
2 
3 f1. prototype = temp;
4 
5 //就是在f1创建的时候,创建了一个它的实例对象并赋值给它的prototype

但这种理解是片面的,因为原型对象中不包含构造函数里的属性和值,是一个空的容器。 

而实例就是通过构造函数实例出来的对象。与实例一样,原型对象就是构造函数实例出来的一个普通对象

可能这一块比较绕,原型对象是在构造函数定义完成时创建一次,但是实例是new一次就通过构造函数构造一次,是属于一对多的关系。

总结: 构造函数中的属性和方法仅为声明和定义,一旦实例化工作完成后。实例对象自身的属性和方法与构造函数将不在存在关联关系。原型对象与实例对象形成“备胎”关系,当通过对象访问属性或方法时,程序会优先搜索对象本身的属性或方法,不存在才会访问原型对象的方法或者属性。

所以考虑到内存的问题,当一个实例需要用到多个方法时,甚至是多个实例需要用到多个同样的方法时,最好的策略就是把方法放在原型对象上,而构造器上仅存放属性,这样能使代码更具有可读性。

讲到方法放在原型对象上时,又要补充一个点,不要以字面量形式的去定义方法或者属性,这样会重写整个原型对象,原型链也会导致变化。应该以添加的方式去定义

 1 //这样会重写整个原型
 2 Fn.prototype = {
 3   c : function() {
 4     return this.a + this.b;
 5   }
 6 }
 7 
 8 //应该以这种形式添加
 9 Rocn.prototype.newFunction = function() {
10     document.write('此方法是通过prototype继承后实现的');
11 }

注意:属性遮蔽 (property shadowing) 即是构造函数内有属性a,在原型上重写属性a,原型上的属性a会被遮蔽,a的值为构造函数上的值。

只要搞懂各种引用指针的指向,就可以清楚地知道原型链的每一部分的指向,原型链的用途就是当需要检索某一属性或者方法时,会通过这些指向,依次检索到相对应标识符的位置为止。 

 

题外:大家可以思考一下construction的作用和功能。我个人的理解就是为了将实例的构造器的原型对象暴露出来

posted on 2020-08-31 15:16  Rocn  阅读(179)  评论(0)    收藏  举报