关于javascript的原型对象的一些理解

         

1、关于原型模式

        有了构造函数模式创建对象为什么还要使用原型模式呢?因为构造函数模式是有缺陷的,我们创建的实例每个方法和属性都要在实例上面重新创建一遍,这样极浪费内存,尤其我们创建的多个实例是为了完成同一件事,那么相应的方法也要创建多次。当然这件事也是有解决方法的,就是把方法的声明放在全局环境中,在构造函数内部设置一个属性指向全局环境中的方法,这样可以解决不用创建多个相同的方法来做同一件事情。但是这样又带来了一个新的问题,如果这个实例要做很多工作呢?是不是要在全局环境中创建相应的方法?但是这样对于我们自定义的这个引用类型就没有封装性了,面向对象的三个重要特征之一的封装性!

还好我们有原型模式,我们不必将方法添加到构造函数中,而是把方法添加到构造函数的原型对象中去,例如:

function Person(){

 

}

Person.prototype._name='xxx';

Person.prototype.talk=function(){

alert(hello~);

}

var p1=new Person();

var p2=new Person();

 

console.log(p1._name+','+p2._name)

可以看到控制台输出了相同的结果,实例p1p2都取到了原型对象中的_name属性

2、什么是原型对象

        当我们创建好一个函数时,也会自动为这个函数创建一个prototype属性,这个属性指向了一个对象,而这个对象就是原型对象。原型对象中包含了特定类型(就是我们创建的引用类型)的所有实例所共享的属性和方法。默认情况下,原型对象会获得一个constructor属性,这个属性指向包含prototype属性的函数(就是我们之前创建的Person构造函数),而我们通过构造函数创建的p1p2实例他们中会有一个指针,它指向了原型对象。下面用图来看一下他们之间的指向关系:

关于javascript的原型对象的一些理解_第1张图片


从这个图可以直观的看见构造函数与他的原型还有他的实例之间的关系:

首先构造函数的prototype属性指向函数原型,而原型的constructor又指向了Person函数;

通过构造函数创建的两个实例都指向了构造函数的原型!从这可以发现通过构造函数创建的对象跟构造函数没有直接的关系,他指向的是函数原型,从这我们也能清楚为什么p1.talk==p2.talk因为他们指向的是同一个对象,引用的是同一块内存区域。

当我们通过p1.talk()调用函数时,解析器是怎么执行的呢?解析器首先检索p1中有没有talk这个方法,如果有,就调用,如果没有就会继续检索p1指向的原型中有没有这个函数,有就调用。这也正是多个实例共享原型所保存的属性和方法的原理。


3、使用原型模式的缺点

      使用原型模式也是有缺点的:

a、他没有为构造函数传递初始化参数,换句话说就是使用构造函数创建对象时,所有实例都取到的相同的默认值。

b、原型模式最大的问题还是其共享的本质导致的,因为所有的实例都共享原型的属性和方法,这种共享对于函数很合适,对于基本类型值的属性也还行,因为我们可以在实例中添加一个同名属性覆盖原型中的属性,但是对于引用类型值的属性就有问题了。如果我们修改了一个实例的引用类型值,那么由于共享,其他实例相应的引用类型值也会被修改,这样每个实例之间就没有个性可言了。

 

4、使用构造函数模式+原型模式克服原型模式的缺点

        我们可以把引用类型值放在构造函数内部,把一般性方法放在原型对象内。这样构造函数模式用于定义实例属性,而原型模式用于定义共享的方法和属性。


你可能感兴趣的:(javascript,javascript,原型对象,原型模式)