一、工厂模式
作用: 创建对象;降低代码冗余度。
优点: 批量创建对象 封装创建对象的函数 提高代码复用率
缺点: 无法区分创建出来的对象种类 方法冗余
将创建对象的代码封装在一个函数中
var getName=function(){
console.log(this.name);
};
function Person(name,age,gender){
return {
name:name,
age:age,
gender:gender,
getName:getName
}
}
var p1=Person('terry',12,'男');
var p2=Person('larry',13,'男');
console.log(p1.getName===p2.getName);//false
console.log(p1 instanceof Object);//true
二、构造函数模式
优点: 可以区分种类
缺点: 方法还是冗余
构造函数本身也是函数,只是以函数的形式为自己的对象类型定义属性和方法。
var getName=function(){
console.log(this.name);
}
function Person(name,age,gender){
this.name=name;
this.age=age;
this.gender=gender;
this.getName=getName;
}
var p1=new Person('terry',12,'男');
var p2=new Person('larry',13,'男');
console.log(p1,p2);
console.log(p1.getName===p2.getName);//true
构造函数模式与工厂模式的区别?
- 共同点: 都是函数,都可以创建对象,都可以传入参数
- 不同点:
-
工厂模式:
- 函数名是小写
- 有返回值
- 直接调用函数就可以创建对象
-
自定义构造函数:
- 函数名是大写(首字母)
- 没有return返回值
- this是当前的对象,属性和方法直接赋值给了 this。
- 通过new的方式来创建对象
- 没有显示地创建对象
-
拓展:
构造函数本身也是函数,如果用new 的方式创建一个实例对象
function Person(name, age, gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
var person1 = new Person("zhangsan", 29, "male");
console.log(person1 instanceof Object)//true
console.log(person1 instanceof Person)//true
console.log(person1 instanceof Function)//true
console.log(Person instanceof Object)//true
console.log(Person instanceof Function)//true
此时自定义的构造函数Person的原型链为:
Person创建出来的实例对象的原型链为:
三、原型模式
将所有的属性和方法都放到原型对象中
,不单独使用
缺点: 它弱化了向构造函数传递初始化参数的能力,会导致所有实例默认都取得相同的属性值
注意: 尽管可以这么做,但并不推荐在产品环境中修改原生对象原型。这样做很可能造成误会,而且可能引发命名冲突。另外还有可能意外重写原生的方法。
function Person() {};
Person.prototype = {
constructor: Person,
name: 'zs',
age: 12,
firends: [],
getName: function() {
console.log(this.name);
}
}
var p1 = new Person();
var p2 = new Person();
console.log(p1.getName === p2.getName); //true
p1.firends.push('ls');
console.log(p1.firends, p2.firends); //[ 'ls' ] [ 'ls' ]
只要给对象实例添加一个属性,这个属性就会遮蔽原型对象上的同名属性,也就是虽然不会修改它,但会屏蔽对它的访问。
function Person() { }
Person.prototype={
name:"zs",
age: 29,
sayName:function () {
console.log(this.name);
};
}
var p1 = new Person();
var p2 = new Person();
// 通过hasOwnProperty()可以查看访问的是实例属性还是原型属性
console.log(p1.hasOwnProperty('name')); //false
p1.name = "lisi";
console.log(p1.name); // lisi,来自实例
//只在重写 p1 上 name 属性的情况下才返回 true,表明此时 name 是一个实例属性,不是原型属性
console.log(person1.hasOwnProperty('name')); //true
console.log(p2.name); // zhangsan,来自原型
console.log(p2.hasOwnProperty('name'));//false
delete p1.name;
console.log(p1.name); // zhangsan,来自原型
四、组合模式(构造函数模式加原型模式)
构造函数中放实例私有的属性,构造函数原型对象中放共有属性和方法
// 在构造函数中 定义一些不需要共享的属性
function Person(name, age, friends) {
this.name = name,
this.age = age,
this.friends = friends
}
// 将要共享的参数或方法定义在原型上
Person.prototype = {
sayName(){
console.log(this.name);
}
}
// 改变构造函数的指向
Object.defineProperty(Person.prototype,'constructor',{
enumerable: false,
value: Person
})
var p1 = new Person('zs', 38, ['ls','ww'])
var p2 = new Person('ls', 40)
console.log(p1.sayName === p2.sayName);//true
这种模式是目前在ECMAScript中使用最广泛,认同度最高的一种创建自定义类型的方法。