一般创建对象是用以下两种方式
new object创建对象:
var Person = new Object(); Person.name = "张三"; Person.age = "18"; Person.job = "123";
或者,对象字面量的方式:
var Person = { name:"lisi", age:"18", job:"123" }
这两种方式的缺点是:同一个接口创建很多对象,会产生大量的重复代码,如var Person1={},var Person2={},为了解决这个问题,人们开始使用工厂模式的一种变体来创建对象。
一、工厂模式
由于在ECMAScript中无法创建类,开发人员就发明了一种函数,用函数来封装以特定接口创建对象的细节,如下图:
function creatPerson(name,age,job){ var a = new Object(); a.name = name; a.age = age; a.job = job; return a; }
var person2 = creatPerson("lisi","17","456");
使用工厂模式创建对象,无论创建多少个对象,都只需要调用creatPerson()函数,并传入相关参数即可。但是工厂模式也留下了一个问题,就是无法区分创建对象类型是什么,在ECMAScript 中的构造函数可用来创建特定类型的对象 。
二、构造函数模式
function Person(name,age,job){ this.name = name; this.age = age; this.job = job; this.sayName = function(){ alert(this.name); } } var person1 = new Person("lisi","18","123");
创建自定义的构造函数,从而定义自定义对象类型的属性和方法 。构造函数也是函数,它与普通函数唯一的区别就是调用方式不同。任何函数,只要用new操作符来调用,那它就可以作为构造函数。
缺点:函数即对象,sayName 是匿名函数对象;每调用实例化一次构造函数就会创建一个匿名函数对象,不同实例上的同名函数是不相等的,占用内存。
三、原型模式
理解原型:只要创建了一个新函数,就会根据一组特定的规则为该函数创建一个 prototype属性,这个属性指向函数的原型对象。
在默认情况下,所有原型对象都会自动获得一个 constructor(构造函数)属性,这个属性包含一个指向 prototype 属性所在函数的指针。
function Person(){ } Person.prototype = { constructor:Person, name:"张三", age:"18", job:"123", friends: ['小明', '小刚'], sayName:function(){ alert(this.name); } } var person1 = new Person();
这里将 Person.prototype 设置为以对象字面量的形式创建的新对象,由于每创建一个新对象,就会同时创建它的 prototype原型对象,
这个对象也会自动获得 constructor 属性,这个constructor指向这个新创建的object对象,而不是Person对象,为了使其指向Person,
需添加 constructor:Person
原型模式的缺点:
var p1 = new Person(); var p2 = new Person(); p2.name = '李四'; p1.friends.push('小红');// 指向同一个friends数组,修改的是原型中的friends console.log(p1.friends);//["小明", "小刚", "小红"] console.log(p2.friends);//["小明", "小刚", "小红"] console.log(p1.friends == p2.friends);//true
缺点1:省略了为构造函数传递初始化参数这一环节,结果所有实例在默认情况下都将取得相同的属性值
缺点2:对于原生构造函数(Object、Array等)的缺点:
p1的friends和p2的friends相同,因为p1修改了原型对象的friends,但我们需要的是它们不应该相同,
解决办法:将需要共享的属性或方法在原型中定义,将不需要共享的如:friends,在构造函数中定义
四、组合使用构造函数和原型模式
构造函数模式用于定义实例属性,而原型模式用于定义方法和共享的属性。结果,每个实例都会有自己的一份实例属性的副本,但同时又共享着对方法的引用,最大限度地节省了内存。
function Person(name,age,job){ this.name = name; this.age = age; this.job = job; this.friends: = ['小明', '小刚'], } Person.prototype = { constructor:Person, sayName:function(){ alert(this.name); } }