简单工厂模式
以Object构造函数或字面量的方式创建对象有着重复性,会产生大量重复代码的缺陷,由此,便出现了工厂模式。
function createObj (name,age) {
var obj = new Object();
obj.name = name;
obj.age = age;
return obj;
}
var obj1 = createObj("小明",66);
var obj2 = createObj("小白",13);
console.log(obj1.name) //小明
console.log(obj2.name) //小白
工厂模式的缺陷
由于新建的所有对象都是Object的实例。所以出现了对象的识别问题
console.log(obj1 instanceof Object) //true
console.log(obj2 instanceof Object) //true
为了解决上述问题,又出现了构造函数模式
function CreateObj (name,age) {
this.name = name;
this.age = age;
this.sayName = function () {
}
}
var obj1 = new CreateObj('小白',19);
var obj2 = new CreateObj('小明',10);
console.log(obj1.name)//小白
console.log(obj2.name)//小明
可以看到工厂模式与构造函数的区别
没有在函数内部新建Object实例 — var obj = new Object();
把属性和方法都添加到了this上。
最后也没有返回值。
注意,函数名的第一个字母是大写,当然没有也可以,但这样做是为了区分构造函数与普通函数的区别,按照惯例是要加上的。事实上,构造函数和普通函数一样,没有什么区别。而当调用函数的时候如果使用了new操作符,那么这个普通的函数就成了一个构造函数。
当使用了new操作符对函数进行调用的时候,后台会新建一个对象,将构造函数作用域赋给新的对象,所以this指针就指向了这个对象。最后是执行构造函数里的代码,这里是给新建的对象中添加了两个属性与方法。
此外,我们可以对这些实例化对象进行识别了。
function CreateObj1 (name,age) {
this.name = name;
this.age = age;
this.sayName = function () {
}
}
function CreateObj2 (name,age) {
this.name = name;
this.age = age;
this.sayName = function () {
}
}
var obj1 = new CreateObj1("小明",11);
var obj2 = new CreateObj2("小红",11);
console.log(obj1.constructor) //CreateObj1 obj1实例的构造函数是CreateObj1
console.log(obj2.constructor) //CreateObj2 obj2实例的构造函数是CreateObj2
console.log(obj1 instanceof CreateObj1) //true obj1从属于CreateObj1
console.log(obj2 instanceof CreateObj2) //true obj2从属于CreateObj2
console.log(obj1 instanceof CreateObj2) //false obj1不从属于CreateObj2
由此解决了对象识别的问题,我们可以知道这些实例对象都从属于谁,而不像工厂模式一样,所以的的实例对象都只是从属于Object。但其实所以的对象都是从属于Object的。
console.log(obj1 instanceof Object) //true
console.log(obj2 instanceof Object) //true
console.log(obj1.__proto__.__proto__ === Object.prototype) //true
但构造函数模式仍存在一些问题,即每个方法都会被重新创建一遍。
function CreateObj1 (name,age) {
this.sayName = function () {
}
}
以上函内在sayName属性上定义了一个方法。而定义一个方法,就会生成一个新的对象。(函数也是对象)
如同 : var sayName = new Function(…)
这样,随着构造函数的每一次调用,就会新建出越来越多的相同的方法,而这些方法的功能都是相同的,浪费了空间。
function CreateObj1 () {
this.sayName = function () {
}
}
var obj1 = new CreateObj1();
var obj2 = new CreateObj1();
console.log(obj1.sayName == obj2.sayName) //false
通过地址的比较可以发现,不同实例之间的方法的引用地址是不同的。
如果说要避免重复创建方法的问题,可以这样做:
function CreateObj1 () {
this.sayName = sayName;
}
function sayName () {
console.log(1)
}
var obj1 = new CreateObj1();
var obj2 = new CreateObj1();
console.log(obj1.sayName == obj2.sayName)//true
我们把函数的定义放到构造函数的外边,然后在构造函数里保存函数的引用地址。从而避免了重复定义函数的问题。
但这种方案存在很多缺陷,并没有被人们所用,缺少封装性,污染全局。解决的方式是通过原型模式来解决。