(1)第一种是工厂模式,工厂模式的主要工作原理是用函数来封装创建对象的细节,从而通过调用函数来达到复用的目的。但是它有一个很大的问题就是创建出来的对象无法和某个类型联系起来,它只是简单的封装了复用代码,而没有建立起对象和类型间的关系。
// 1.工厂模式
// 区分不清对象和原型的联系
function Dog(name, age) {
var obj = new Object();
obj.name = name;
obj.age = age;
return obj;
}
var d1 = Dog('xiaobai', 2);
var d2 = Dog('xiaohei', 1);
console.log(d1, d2);//{ name: 'xiaobai', age: 2 } { name: 'xiaohei', age: 1 }
缺点:类型无法区分,所有通过该方式创造的对象的构造函数都是Object.
(2)第二种是构造函数模式。js 中每一个函数都可以作为构造函数,只要一个函数是通过 new 来调用的,那么我们就可以把它称为构造函数。构造函数模式相对于工厂模式的优点是,所创建的对象和构造函数建立起了联系,因此我们可以通过原型来识别对象的类型。
但是构造函数存在一个缺点就是,造成了不必要的函数对象的创建。
// 2、构造函数
function Dog1(name, age) {
this.name = name;
this.age = age;
this.sayName = function() {
console.log(this.name);
} //每次创建对象,都会创建一个新的函数,可以单独拿出来,但是封装性变差了
}
缺点:造成了不必要的函数对象的创建
(3)第三种模式是原型模式,因为每一个函数都有一个 prototype 属性,这个属性是一个对象,它包含了通过构造函数创建的所有实例都能共享的属性和方法。因此我们可以使用原型对象来添加公用属性和方法,从而实现代码的复用。这种方式相对于构造函数模式来说,解决了函数对象的复用问题。但是这种模式也存在一些问题,一个是没有办法通过传入参数来初始化值,另一个是如果存在一个引用类型如 Array 这样的值,那么
所有的实例将共享一个对象,一个实例对引用类型值的改变会影响所有的实例。
// 3.原型模式
console.log('原型模式');
function Dog2() {}
// 在prototype中定义的属性和方法,所有的实例都共享
Dog2.prototype.name = 'xiaobai';
Dog2.prototype.age = 2;
Dog2.prototype.sayName = function() {
console.log(this.name);
}
var dog1 = new Dog2();
console.log(dog1);
dog1.sayName();
dog1.name = 'lisi';
dog1.sayName();
console.log(dog1);
(4)第四种模式是组合使用构造函数模式和原型模式,这是创建自定义类型的最常见方式。因为构造函数模式和原型模式分开使用都存在一些问题,因此我们可以组合使用这两种模式,通过构造函数来初始化对象的属性,通过原型对象来实现函数方法的复用。这种方法很好的解决了两种模式单独使用时的缺点,但是有一点不足的就是,
因为使用了两种不同的模式,所以对于代码的封装性不够好。
// 4.组合模式
// ES5中比较完美的
function Dog4(name, age) {
this.name = name;
this.age = age;
this.arr = []; //重复创建,不会出现影响
}
Dog4.prototype.sayName = function() {
console.log(this.name);
}