工厂模式
1 function createPerson(name,age,job){ 2 var o = new Object(); 3 o.name = name; 4 o.age = age; 5 o.job = job; 6 o.sayName = function(){ 7 console.log(this.name); 8 } 9 return o; 10 } 11 12 var person1 = createPerson("Nicholas",29,"SoftWare Engineer"); 13 var person2 = createPerson("Greg",23,"Doctor");
工厂模式虽然解决了创建多个相似对象的问题,但却没有解决对象识别的问题(即怎么样知道一个对象的类型)
构造函数模式
1 function Person(name,age,job){ 2 this.name = name; 3 this.age = age; 4 this.job = job; 5 this.sayName = function(){ 6 console.log(this.name); 7 }; 8 } 9 10 var person1 = new Person("Nicholas",29,"SoftWare Engineer"); 11 var person2 = new Person("Greg",23,"Doctor");
Person()中的代码除了与createPerson()中相同的部分外,还存在以下不同之处:
1、没有显示的创建的对象
2、直接将属性和方法赋给了this对象
3、没有return语句
按照惯例,构造函数始终都应该以一个大写字母开头,而非构造函数则应该以一个小写字母开头。
要创建Person的新实例,必须使用new操作符。以这种方式调用的构造函数实际上会经历一下4个步骤
1、创建一个新对象
2、将构造函数的作用域赋给新对象
3、执行构造函数中的代码(为这个新对象添加属性)
4、返回新对象
person1和person2分别保存着Person的一个不同的实例。这两个对象都有一个constructor(构造
函数)属性,该属性指向Person
1 alert(person1.constructor == Person); //true 2 alert(person2.constructor == Person); //true
但是,提到检测对象的类型,还是instanceof操作符更可靠一些,上面的例子中创建的所有对象即是
Object的实例,也是Person的实例。
1 console.log(person1 instanceof Object); //true 2 console.log(person1 instanceof Person); //true
创建自定义的构造函数一意味着将来可以将它实例标识为一种特定的类型;而这正是构造函数模式
胜过工厂模式的地方。
1、将构造函数当做函数
构造函数与其他函数的唯一区别,就在于调用他们的方式不同。任何函数,只要通过new操作符来调用,
那他就可以作为构造函数,而任何函数如果不通过new操作符来调用,那他和普通函数没什么差别
1 //当做构造函数使用 2 var person = new Person("Nicholas",29,"Software Engineer"); 3 person.sayName(); //Nicholas 4 5 //作为普通函数调用 6 Person("Greg",27,"Doctor"); 7 window.sayName(); //Greg 8 9 //在另一个对象的作用域中调用 10 var o = new Object(); 11 Person.call(o,"Kristen",25,"Nurse"); 12 o.sayName(); //Kristen
2、构造函数的问题
构造函数的主要问题就是每个方法都要在每个实例上重新创建一遍,person1和person2都有一个名为
sayName()的方法,但那两个方法不是同一个Function实例
1 console.log(person1.sayName == person2.sayName); //false
为了解决这个问题,通常将函数定义转移到构造函数外面
1 function Person(name,age,job){ 2 this.name = name; 3 this.age = age; 4 this.job = job; 5 this.sayName = sayName; 6 } 7 8 function sayName(){ 9 console.log(this.name); 10 } 11 12 var person1 = new Person("Nicholas",29,"SoftWare Engineer"); 13 var person2 = new Person("Greg",23,"Doctor");
这样一来就又出现了新的问题,在全局作用域中定义的函数sayName()只能被某个对象调用,这让全局作用域有点名不副实。更加严重的是,如果对象需要定义很多方法,那么就要定义很多个全局函数,于是我们这个自定义的引用类型就丝毫没有封装性可言了,这些问题都可以通过原型模式来解决