工厂模式
1 | function creatStudent(name,age){ |
1 | stu1=creatStudent('zjn',20); |
工厂模式虽然或以创建多个类似的对象,但是却无法识别对象,不知道一个对象是什么类型的。
构造函数模式
1 | function Student(name,age){ |
这个写法改写了工厂模式的那个例子,Person()就是一个构造函数,构造函数应该以大写字母开头。
new一个对象出来经历4个步骤:
- 创建一个新的对象
- 将构造函数作用域给新对象(那样this就指向了新对象)
- 执行构造函数中的代码(给新对象添加属性和方法)
- 返回新对象
上面例子中的stu1对象有一个constructor属性,指向Student.
1 | alert(stu1.constructor==Student) //true |
所以constructor>能够识别对象类型,但用instanceof来检测对象类型更好,上面创造的stu1对象既是Student的实例,也是Object的实例,因为所有的对象都继承自Object对象。
1 | alert(stu1 instanceof Student) //true |
原型模式
像上面的Student这样的构造函数会有一个prototype属性,这个属性指向prototype对象(原型对象)。这个对象包含共享的属性和方法。
1 | function Student(name,age){ |
在默认情况下,原型对象(prototype对象)会自动获得一个constructor属性,这个属性又指向prototype属性所在的函数,如Student.prototype.constructor就指向Student这个函数本身。
除此之外,原型对象还会有一个proto属性,这个属性指向Object原型对象。
实例化一个对象后,这个实例会有一个proto属性,这个属性指向构造函数的原型对象。比如stu1的proto属性指向Student的原型对象。
按照下图理解
在实例中添加一个原型中已经有的属性,会屏蔽原型中的同名属性。可以用hasOwnProperty()来检测对象上是否有这个属性。
1 | console.log(stu1.hasOwnProperty('name'));//true |
关于原型重写的问题
同样是之前使用的那个例子,如果我们要加原型方法或属性需要不断的写Student.prototype.xxx=xxx,我们可以重写原型来减少体力劳动。
1 | function Student(name,age){ |
这样做有什么问题呢? 因为我们写了一个prototype的对象,所以它会创建自己的prototype对象,里面的constructor属性将指向Object。也就是本该指向Student的prototype对象中的constructor不再指向Student。
组合使用构造函数模式和原型模式
所以要引出这个模式,将有引用类型的属性放到构造函数中,使每个实例都有一个副本,不会相互影响。
1 | function Student(name,age){ |
本文转自GaNan’s Blog