我们构建了一个对象Obj,它有一个属性name,一个方法showName。但是如果我们要再构建一个类似的对象呢?难道还要再重复一遍? NO!,我们可以用一个返回特定类型对象的工厂函数来实现。就像工厂一样,流水线的输出我们要的特定类型结果。 【工厂方式】 复制代码 代码如下: function createObj(name) { var tempObj = new Object; tempObj.name = name; tempObj.showName = function () { alert(this.name); }; return tempObj; } var obj1 = createObj("obj_one"); var obj2 = createObj("obj_two");
这种工厂函数很多人是不把他当做构建对象的一种形式的。一部分原因是语义:即它并不像使用了运算符new来构建的那么正规。还有一个更大的原因,是因为这个工厂每次产出一个对象都会创建一个新函数showName(),即每个对象拥有不同的版本,但实际上他们共享的是同一个函数。 有些人把showName在工厂函数外定义,然后通过属性指向该方法,可以避开这个问题: 复制代码 代码如下: function showName () { alert(this.name); } function createObj(name) { var tempObj = new Object; tempObj.name = name; tempObj.showName = showName; return tempObj; } var obj1 = createObj("obj_one"); var obj2 = createObj("obj_two");
可惜的是,这种方式让showName()这个函数看起来不像对象的一个方法。 【构造函数方式】 这种方式是为了解决上面工厂函数的第一个问题,即没有new运算符的问题。可是第二个问题它依然不能解决。我们来看看。 复制代码 代码如下: function Obj(name) { this.name = name; this.showName = function () { alert(this.name); } } var obj1 = new Obj("obj_one"); var obj2 = new Obj("obj_two");
【原型方式】 这种方式对比以上方式,有个很大的优势,就是它解决了方法函数会被生成多次的问题。它利用了对象的prototype属性。我们依赖原型可以重写对象实例。 复制代码 代码如下: var Obj = function () {} Obj.prototype.name = "me"; Obj.prototype.showName = function () { alert(this.name); } var obj1 = new Obj(); var obj2 = new Obj();
我们依赖原型对构造函数进行重写,无论是属性还是方法都是通过原型引用的方式给新建的对象,因此都只会被创建一次。可惜的是,这种方式存在两个致命的问题: 1。没办法在构建对象的时候就写入想要的属性,因为原型在构造函数作用域外边,没办法通过传递参数的方式在对象创建的时候就写入属性值。只能在对象创建完毕后对值进行重写。 2。致命问题在于当属性指向对象时,这个对象会被多个实例所共享。考虑下面的代码: 复制代码 代码如下: var Obj = function () {} Obj.prototype.name = "me"; Obj.prototype.flag = new Array("A", "B"); Obj.prototype.showName = function () { alert(this.name); } var obj1 = new Obj(); var obj2 = new Obj(); obj1.flag.push("C"); alert(obj1.flag); // A,B,C alert(obj2.flag); //A,B,C