在上一篇文章中,我们了解了JS中创建对象的几种形式,最后一种是构造函数模型,我们提到了利用构造函数创造对象时,方法没有实现共享,这一篇我们将用实例来讲解一下创建对象的另一种方法——原型模式。

如果对JS如何创建对象还不是很了解,建议先去看一下详解JS的对象以及创建对象的N种方式再回来。

一 JS中prototype,__proto__,constructor的关系

在JS中,当我们创建一个函数的时候,就根据一组特定的规则给这个函数创建一个prototype属性,这个属性指向这个函数的原型对象。在默认情况下,每个原型对象都会自动获得一个constructor属性,这个属性指向这个函数。来看下面的代码:


上面的代码中,新建了一个Person对象,然后在Person的原型对象上(Person.prototype)添加了属性和方法,Person的原型对象有个constructor属性,指向Person。通过new Person()创建了两个实例对象person1和person2,person1的__proto__指向的就是Person的原型对象。下图表明了上述关系。


二 在原型对象中查找值


在上面的代码中,person1中也有个name属性,在调用sayName方法时,会先在实例对象中查找name,如果有,返回name,如果没有,则继续在原型对象中查找,依次向上,直到找到或者没找到返回null。虽然可以通过对象实例访问原型对象中的值,但是却不能通过实例对象重写原型中的值。如果在实例对象中已经找到了name属性,则自动屏蔽掉原型对象中的值。不过,通过delete操作符可以删除实例属性。


三 检测属性是在实例中还是原型对象中

使用hasOwnProperty()可以检测出实例对象是否具有某个属性,如果是原型属性统一返回false.


使用in操作符不管属性是在实例中还是原型对象中,都会返回true.


四 原型对象的问题

前面我们将共享的属性写在原型对象中,解决了构造函数模式和工厂模式中不共享的问题。但是原型对象模式也存在问题,原型对象对于函数和基本类型的共享不存在问题,因为基本类型可以屏蔽掉原型,但是对于引用类型的属性则存在一定的影响,看下面的例子:


给person1又添加了一个朋友后,person2也多了这个朋友。这时候原型模式也存在问题了。

五 组合使用构造函数模式和原型模式

要解决上面的问题,我们可以组合使用构造函数模式和原型模式,对于私有的属性,在构造函数中定义,对于共享的属性在原型中定义。


以上,就是所有原型对象,原型模式的内容,在以后创建对象时,灵活选择合适的模式。如果有问题,欢迎交流。


本文转载:CSDN博客