Javascript理解面向对象(一):对象创建模式
1)工厂模式
通俗来讲就是把原料进厂加工后出厂的一系列流程。在这里只是把原料换成了数据。
以下代码创建了一个createPerson()函数,函数中存在两个属性一个方法,可用于添加并打印person的姓名和年龄信息。
<script> function createPerson(name, age) { //1:原料 var obj = new Object(); //2:加工 obj.name = name; obj.age = age; obj.showInfo = function () { alert(this.name + ',' + this.age); }; //3:出厂 return obj; } var p1 = createPerson('leo', 22); var p2 = createPerson('su', 37); p1.showInfo(); //leo,22 p2.showInfo(); //su,37 alert(p1.showInfo == p2.showInfo); //false </script>
这种工厂模式是比较原始的一种对象创建模式,其中存在两种比较明显的缺陷。
缺陷一:无法识别对象类型 也就是没有new的过程
缺陷二:每个对象都需要创建一个showInfo() 方法造成了资源浪费
2)构造函数模式
Js中的构造函数可用来创建特定类型的对象。像Object和Array这样的原生构造函数,在运行时会自动出现在执行环境里。
此外,也可以创建自定义的构造函数,从而定义自定义对象类型的属性和方法。使用构造函数模式重写前面的例子。
<script> function createPerson(name, age) { //系统内部自动创建this对象 //var this = new Object(); //2:加工 this.name = name; this.age = age; this.showInfo = function () { alert(this.name + ',' + this.age); }; //系统自动返回对象 //return this; } var p1 = new createPerson('leo', 22); var p2 = new createPerson('su', 37); p1.showInfo(); //leo,22 p2.showInfo(); //su,37 </script>
当前模式解决了工厂模式存在的第一个缺陷,但第二个缺陷仍然存在。在这个模式下alert(p1.showInfo==p2.showInfo),结果仍然是false.
每个方法都要在每个对象实例上重新创建一遍,但本质上这些方法是相同的。
3)原型模式
关于原型对象不做深入探讨,以后再讲它的工作原理。现在只需要知道使用原型对象的好处是可以让所有对象实例共享他所包含的属性和方法。
看一个Array对象的例子。给数组对象实现一个sum求和方法。
<script>
// Array类 本身不具备实际功能 只能用来构造对象 // arr对象 本身具备实际功能 是被类创造出的 var arr1 = new Array(1, 3, 5, 7); var arr2 = new Array(1, 2, 5); arr1.sum = function () { var result = 0; for (var i = 0; i < this.length; i++) { result += this[i]; } return result; }; alert(arr1.sum()); //16 alert(arr2.sum()); //弹出错误 </script>
alert(arr2.sum());这条语句很明显会弹出错误,因为我并没有创建arr2.sum方法,创建的是arr1.sum()。
如果要实现对arr2对象数组的求和,那就要再把求和函数赋值给arr2.sum。这样既麻烦又浪费了系统资源。
我们用prototype原型对象模式来重写一下。
<script> var arr1 = new Array(1, 3, 5, 7); var arr2 = new Array(1, 2, 5); //可用于扩展系统函数功能 Array.prototype.sum = function () { var result = 0; for (var i = 0; i < this.length; i++) { result += this[i]; } return result; }; alert(arr1.sum == arr2.sum); //true alert(arr1.sum()); //16 alert(arr2.sum()); //8 </script>
这样就用prototype模式为Array对象增加了一个新方法sum(),它的性质和数组原本的pop()、push()、sort()等方法是一样的。每个对象都可以使用它。
现在再来看一下最开始的例子。我用prototype模式重写了它。
<script> //相同的东西加在原型里 不同的东西加在构造函数里 //首字母大写以区别构造函数和普通函数 function CreatePerson(name, age) { //属性:每个对象各不相同 过程、动态 this.name = name; this.age = age; } //方法:所有对象都一样 状态、静态 CreatePerson.prototype.showInfo = function () { alert(this.name + ',' + this.age); }; var p1 = new CreatePerson('leo', 22); var p2 = new CreatePerson('su', 37); alert(p1.showInfo==p2.showInfo) //true p1.showInfo(); //leo,22 p2.showInfo(); //su,37 </script>
上例正确打印出了person信息,并打印出两个对象实例的方法是相同的。
由此,我们在实际项目中可以为系统函数增加新的方法以扩展功能满足需求并节省资源。也可在自己构造的函数中增加原型方法使实例共享以节省资源。