创建对象的几种模式

一般创建对象是用以下两种方式

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);
    }
}
原文地址:https://www.cnblogs.com/johnhery/p/9901979.html