常用的使用字面量或Object构造函数来创建对象的时候,如果需要创建多个具有相同属性不同属性值的对象时,会产生大量的重复代码,这无疑对于代码的书写和阅读都有极大的不便利。为了解决这个问题,工厂函数应运而生。
1.工厂模式
由于在js中无法创建类,故使用封装函数的方式,封装以特定接口创建对象的细节,在调用的时候,可直接根据接受的参数,来构建包含所有必要信息的对象。如下:
<script>
function createPerson(name , age , sex){
var obj = new Object();
obj.name = name;
obj.age = age;
obj.sex = sex;
obj.show = function(){
console.log("姓名:" + obj.name + " 年龄:" + obj.age + " 性别:" + obj.sex);
}
return obj;
}
var person1 = createPerson("旦旦" , 20 , "男");
var person2 = createPerson("旦旦boom" , 20 , "male");
person1.show();//姓名:旦旦 年龄:20 性别:男
person2.show();//姓名:旦旦boom 年龄:20 性别:male
</script>
使用工厂函数,有效地避免了重复创建对象时需要重复书写相似代码的问题,但却没有解决对象类型的识别问题。
2.构造函数模式
与工厂模式不用,我们在用自定义的构造函数创建对象时,无需显式创建对象、直接把属性和方法付给this且没有return语句。如下:
<script>
function Person(name , age , sex){
this.name = name;
this.age = age;
this.sex = sex;
this.show = function(){
console.log("姓名:" + this.name + " 年龄:" + this.age + " 性别:" + this.sex);
}
}
var person1 = new Person("旦旦" , 20 , "男");
var person2 = new Person("旦旦boom" , 20 , "male");
person1.show();//姓名:旦旦 年龄:20 性别:男
person2.show();//姓名:旦旦boom 年龄:20 性别:male
</script>
按照惯例,构造函数通常应该采取大驼峰的命名方式,而非构造函数则应该采取小驼峰的命名方式。构造函数的这个命名方法主要是借鉴子其他OO语言,为了区别于其他函数。
创建自定义的构造函数意味着将来可以将它的实例标识为一种特定的类型,这正是构造函数模式胜过工厂模式的地方。在上面这个例子中,person1和person2既是Person的实例,又是Object的实例。
console.log(person1 instanceof Object);//true
console.log(person1 instanceof Person);//true
console.log(person2 instanceof Object);//true
console.log(person2 instanceof Person);//true
虽然在类型识别上构造函数体现了优势,但构造函数也有一个大问题,就是构造函数在创建实例对象的时候,每次都会将函数体内预先设置的属性和方法都设置一遍,如person1和person2中的show方法。如下:
console.log(person1.show == person2.show);//false
用构造函数多次实例对象,会导致不同的作用域和标识符解析,这无疑会浪费掉一部分性能。这也是构造函数最大的问题。
ps:new操作符调用构造函数的步骤
1.创建一个新对象
2.对这个新对象执行[[Prototype]]连接
3.将this绑定到这个空对象上,执行构造函数中的代码
4.返回新对象
3.原型模式
我们创建的每个函数都有一个prototype属性,这个属性是一个指针指向一个对象,这个对象的用途是储存可以由特定类型的所有实例对象共享的属性和方法。相对于构造函数而言,我们只需要将储存的方法储存到prototype原型对象中,就可以让由这个构造函数实例出来的所有对象都共享这些方法,而不需要每次都将这些方法实例出来。如下:
<script>
function Person(name , age , sex){
this.name = name;
this.age = age;
this.sex = sex;
Person.prototype.show = function(){
console.log("姓名:" + this.name + " 年龄:" + this.age + " 性别:" + this.sex);
}
}
var person1 = new Person("旦旦" , 20 , "男");
var person2 = new Person("旦旦boom" , 20 , "male");
person1.show();//姓名:旦旦 年龄:20 性别:男
person2.show();//姓名:旦旦boom 年龄:20 性别:male
console.log(person1.show === person2.show);//true
</script>
在此,我们将show方法添加到了Person函数的prototype属性中,person1和person2实例都共享了这个方法,通过验证也得知这两个实例的show方法指向了同一个方法。