1工厂模式 过程: 使用newObject()显示创建一个obj对象 把属性和方法直接添加到obj对象上 return返回该obj对象 缺点:工厂模式不能识别对象的类型。2构造函数模式 改写上述代码: createPerson函数改成了Person函数 构造函数模式与工厂模式的区别还有: 没有显示地创建对象(没有用newObject()) 把属性和方法直接添加到this对象 不需要return语句 过程: 通过newPerson()创建一个新对象 构造函数Person的作用域指向新对象,即this指向了新对象 执行构造函数中的代码,即把属性和方法添加到this上 返回新对象 注意: person1与person2保存着Person不同的实例。 两个对象都有一个constructor属性,constructor属性指向Person; console。log(person1。constructor);Person console。log(person2。constructor);Person 也就是说,自定义构造函数的实例可以通过constructor属性来唯一标识其为特定的类型。(这是工厂模式做不到的) alert(person1instanceofPerson);true; alert(person2instanceofPerson);true; alert(person1instanceofObject);true; alert(person2instanceofObject);true; 构造函数模式的缺点 缺点一、会创建多个完成相同任务的同名Function实例 同上面的例子: Person的两个实例person1和person2,各自都有一个sayName方法。但person1。sayName和person2。sayName不是一样的,即这两个方法各自都是Function的一个实例。 因为,ECMAScript的函数都是对象,其实可写作newFunction(): this。sayNamefunction(){ console。log(this。name); } 可以写作 this。sayNamenewFunction(console。log(this。name)); 也就是说:通过自定义构造函数模式,每通过newPerson()实例一个新的对象,也就创建了一个新的Function实例。每个person中的sayName方法是不一样的,是不同的实例。虽然他们之间有相同的名字、处理的代码相同。 每创建一个新的Person实例,就又附带创建了新的Function实例。而这些Function实例,同名又干一样的事情,确实是没有必要! 如何规避? 将Person中sayName函数的定义放到构造函数的外部,改写如下: functionPerson(name,age,job){ this。namename; this。ageage; this。jobjob; this。sayNamesayName; } functionsayName(){ console。log(this。name); } 相当于在构造函数Person内部的sayName属性设置为全局函数sayName()。this。sayName则是一个指针,指向这个全局函数。 这样就可以让多个Person实例的this。sayName属性都指向这个全局函数,从而没有创建过多的同名Function实例(干同样的事)。 缺点二、全局函数 看样子把构造函数内部的方法,定义到外部作全局函数就可以解决问题了。 但是这个定义在全局作用域的函数,却只能给某类对象使用,听起来就怪怪的。 还有,如果某构造函数需要很多方法,为了避免创建过多同名Function实例,难道我们要在全局作用域定义很多个函数吗?!3原型模式 原型模式可以改善构造函数模式的缺点: 4关于原型对象: 我们创建的函数都具有一个prototype属性,该属性是个指针,指向该函数的原型对象。 原型对象:可以让所有对象的实例共享它所包含的属性和方法 原型对象都有一个constructor属性,该属性也是个指针,指向prototype属性所在的函数。 因为Person。prototype原型对象,可以让Person的所有实例都共享它所包含的属性和方法。 那也就不会像构造函数模式那样,需要创建许多同名Function实例或者在全局作用域定义许多个函数了。 即,Person。prototype指向原型对象; Person。prototype。constructor指向Person; Person创建的实例person1与person2,〔〔prototype〕〕,仅仅指向Person。prototype(原型对象),与构造函数Person没有直接关系。 原型模式的搜索 当代码读取某个对象实例的某个属性时,是先从该实例上搜索查找有无该属性,若在实例本身check到了,那就返回该属性的值;如果在实例上找不到,那继续往上找,找实例的原型对象(Person。prototype)看有没有该属性。 这也是为什么不同实例能共享原型对象里的属性和方法。 简单的语法 可以这么写: functionPerson(){}; Person。prototype{ name:John, age:22, job:enginee, sayName:function(){ console。log(this。name); } } varperson1newPerson; console。log(person1。constructorObject);true; console。log(person1。constructorPerson);false; 因为说过,Person。prototype会有个constructor属性,这个属性指向prototype属性所在的函数。可见prototype现在没有写在Person里面了,而是在Object上。 但是可以手动修改 functionPerson(){}; Person。prototype{ constructor:Person, name:John, age:22, job:enginee, sayName:function(){ console。log(this。name); }5组合使用构造函数模式与原型模式 原型模式中的prototype原型对象,是给实例提供所有共享的方法和属性,但有的若是引用类型,则不适合被共享。 那么就在构造函数模式中,定义实例属性(不希望被共享);用原型模式来为实例定义可以被共享的属性和方法。