JavaScript创建对象的模式
/** * Created by W_YH on 2016/3/14. */ /* 对象的创建方式 */ //------->第一种创建方式------创建Object的实例 var person= new Object(); person.age=20; person.name='milk'; person.say=function(){ console.log(this.age+this.name); }; //------->第二种方式-----对象字面量 var person={ name:'milk', age:20, say:function(){ console.log(this.name+this.age); } }; // 使用Object()构造函数和对象字面量形式创建单个对象的弊端:使用一个接口创建很多对象,会产生大量的重复代码 //------->第三种方式-----工厂模式 function creatFactor_person(name,age){ var o= new Object(); o.name=name; o.age=age; o.say=function(){ console.log(this.name+this.age); }; return o; } var person1=creatFactor_person('milk',20); //工厂模式:不同参数会构造出不同的对象,不在单纯依赖Object实例; // :解决了创建多个相似对象的问题,但却无法区分一个对象的类型: //------->第四种方式-----构造函数模式 function CreatConstr_person(name,age){ this.name=name; this.age=age; this.say=function(){ console.log(this.name+this.age); }; } /*调用new操作符经历的4个过程: * 1.创建一个新对象 * 2.将构造函数的作用域赋给新对象(this指向这个新对象) * 3.执行构造函数中的代码(为新对象添加属性) * 4.返回新对象 * */ var person1=new CreatConstr_person('milk',20); //使用对象的 constructor属性标识对象类型 ,也可以通过 instanceof 进行检测.使用构造函数模式可以确定对象的类型 console.log(person1 instanceof CreatConstr_person);//true //构造函数模式优于工厂模式在于可以将构造函数模式的实例标识为一种特定的类型。 /*缺点: *每个方法都要在每个实例上重新创建一遍,比如以上例子 创建多个对象,每个对象都具有一个say()方法且互不相同(每次都相当于调用new Function()操作), 这样实现同样任务的方法,却被创建多次,完全没有必要,不符合函数共享的本质,所以引入以下方式,将构造函数的方法放置外部 * */ function CreatConstr2_person(name,age){ this.name=name; this.age=age; this.say=say; } function say(){ console.log(this.name+this.age); } //以上方式虽然 解决了创建两个(不同)函数解决同一个事情的问题,但却如果对象需要过多的方法,就会造成全局函数过多,且全局函数只被某个对象调用,似乎有些浪费 var person=new CreatConstr2_person('milk',20); //------->第五种方式-----原型模式 function CreatConstr3_person(){} CreatConstr3_person.prototype.name='milk'; CreatConstr3_person.prototype.age=20; CreatConstr3_person.prototype.say=function(){ console.log(this.name+this.age); } var person=new CreatConstr3_person(); //原型对象,解决了通过构造函数完成同一功能方法反复创建且创建的不同实例对象的方法不同的问题(两个(不同)函数解决同一个事情的问题); //简化操作,原型对象字面量形式 function CreatConstructor4_person(){} CreatConstructor4_person.prototype={ name:'milk', age:20, say:function(){ console.log(this.name+this.age); } }; var person=new CreatConstructor4_person(); //这时会出现原型对象的constructor指向的问题(相当于重写原型,默认指向Object()),可显式指定其指向;参见高程P155。 //原型模式的缺点:1.原型模式省略了为构造函数传参的步骤,所以创建出的所有实例,均具有相同的属性和方法----工厂模式和构造函数模式由于传参不存在该问题 //原型模式另一个缺点是:由原型模式共享本质所引起的(共享对于函数来说是极好的,基本类型属性也可通过实例覆盖,但对于引用类型就比较麻烦) //共享导致所有实例都可以访问别的实例所添加 的引用类型属性,大家都具有一样的属性,无隐私可言 //------->第六种方式-----组合使用构造函数和原型模式 //构造函数用于定义实例属性,原型模式定义方法和共享的属性。 function CreatConstructor5_person(age,name){ this.name=name; this.age=age; this.friends=[]; } CreatConstructor5_person.prototype={ constructor:CreatConstructor5_person, say:function(){ console.log(this.name+this.age+this.friends); } } var person1=new CreatConstructor5_person(20,'milk'); person1.friends.push('AS'); //------->第七种方式-----动态原型模式 // 把所有的信息封装在构造函数中,(仅在需要时创建)在构造函数中初始化原型,又同时保持使用构造函数和原型的优点 function CreatConstructor6_person(name,age){ this.name=name; this.age=age; if(typeof(this.say)!="function"){ CreatConstructor6_person.prototype.say=function (){ console.log(this.name+this.age); } } } var person1= new CreatConstructor6_person('milk',20); //寄生构造函数模式:和工厂模式一样,但创建实例时,需要使用new操作符; //稳妥构造函数模式:没有公共属性,且方法也不引用this对象;与寄生模式不同点:实例方法不引用this,不使用new调用构造函数 //导致外部无法访问内部数据 function person(name,age){ var o=new Object(); o.say=function (){ console.log(name); } }