前天就在看面象对象设计这一章了,可是总是迷迷糊糊,今天又看了一遍,又看了云课堂里面的关于js的视频,才是真的对创建对象有了一点理解;现在对这一节做一个总结。创建对象的方法在这本书中一共提到了工厂模式、构造函数模式、原型模式,组合使用构造函数模式和原型模式、动态原型模式,寄生构造函数模式、稳妥构造函数模式7种,其中以构造函数和原型模式为主,原型模式就是重中之重了吧,同时,我觉得也以原生模式最为烧脑壳子,我当时就是因为它一度不下看下去这本书,不过,当你静下心来,慢慢想的时候,事情就变得简单了,不多说,作总结。
工厂模式:优点:实现函数封装,可以解决大量重复相似实例的问题,减少代码;
缺点:无法解决对象识别的问题;如:
function box(name,age){ var o=new Object(); o.name =name; o.age=age; o.sayName = function(){ alert(this.name); }; return o; } var box1=box("zhangsan",21); var box2=box("zhangsan",21); alert(box1 intanceof Object);//true; alert(box2 intanceof Object);//true;
上面代码返回值一样。所以没有解决对象识别的问题;
构造函数模式:构造函数在运行时会自动出现在执行环境中,也可以创建自定义的构造函数,从而定义自己定义的对象的属性和方法;构造函数的特点:1,没有显示的创建对象,2、直接将属性和方法赋给了this对象;3,没有return语句;4,构造函数函数名首字母大写;5、必须使用new操作符来创建新实例;如:
function Box(name,age){ this.name =name;//this代表的是当前作用域下的对象,在这里指Box; this.age=age; this.sayName = function(){ alert(this.name); }; } var box1=new Box("zhangsan",21); var box2=new Box("zhangsan",21);
创建自定义的构造函数意味着我们可以将它的实例标示为一种特定的类型,这也是构造函数优胜于工厂模式的地方;但是构造函数模式也有问题,就是每个方法都要在每个实例上创建一遍,也就是不同实例的同名函数是不等的,虽然值是一样的,但是引用地址不一样:如
function Box(name,age){ this.name =name;//this代表的是当前作用域下的对象,在这里指Box; this.age=age; this.sayName = function(){ alert(this.name); }; } //function sayName(){ alert(this.name);这是全局的sayName,this表示window; } var box1=new Box("zhangsan",21); var box2=new Box("zhangsan",21); alert(box1.sayName==box2.sayName)//false;
为了解决这个问题,我们看而已把方法写到全局环境中,从而实现引用地址的一致性,但是如果这个样的话,函数就没有实现封装了,哎!那么现在就该放大招,用原型了,真是“山穷水尽疑无路,柳暗花明又一村”。
原型模式:我们创建的每个函数都有一个prototype属性,它是一个对象的引用,而这个对象包含了特定类型的所有实例共享的属性和方法,也称为通过构造函数创建的实例对象的原型对象,当然好处就是共享了;如:
function Box(){};//函数中不对属性进行定义;利用prototype属性对属性进行定义; Box.prototype.name ="zhangsan";//this代表的是当前作用域下的对象,在这里指Box; Box.prototype.age=21; Box.prototype.sayName = function(){ alert(this.name); }; var box1=new Box("zhangsan",21); box1.sayName();//"zahngsan" var box2=new Box("zhangsan",21); box2.sayName();//"zahngsan" alert(box1.sayName==box2.sayName);//true; alert(Box.prototype.isPrototypeOf(box1));//true;这个用来测试实例是否指向了构造函数的原型对象; alert(Object.getPrototypeOf(box1)==Box.prototype);//true;这个方法用来返回对象的原型;
原型中的几个方法:
hasOwnProperty():检测构造函数中是否含有实例属性;如果有,返回true;
in操作符:检测是否含有可以访问的属性,包括实例属性和原型属性;
hasPrototypeProperty(():来检测属性是否是原型属性;
原型对象的缺点:1、省略了传参,使得所有初始化值一样;2、共享,使实例不具有独立性;为了解决这个问题。采用组合“构造函数和原型”的方法,如:
function Box(name,age){ this.name =name;//this代表的是当前作用域下的对象,在这里指Box; this.age=age; this.family=["哥哥","姐姐"]; } Box.prototype ={ constructor:Box, sayName:function(){ alert(this.name); } } var box1=new Box("zhangsan",21); var box2=new Box("zhangsan",21); box1.family.push("弟弟"); alert(box1.family);//"哥哥","姐姐","弟弟" alert(box2.family);//"哥哥","姐姐" alert(box1.sayName==box2.sayName);//true; alert(box1.family==box2.family);//false
可以看出这样可以实现实例的独立性;由于原型和构造函数分离,不便于引用,这就有了动态原型模式实现构造函数和原型的封装;
function Box(name,age){ this.name =name;//this代表的是当前作用域下的对象,在这里指Box; this.age=age; this.family=["哥哥","姐姐"]; if(typeof this.sayName!="function"{ Box.sayName=function(){ alert(this.name); }; } } var box1=new Box("zhangsan",21); box1.sayName();
这种方法特别使用,但要注意这种方法中不能使用字面量重写原型;
总的来说,原型模式和构造函数本就是武林高手,当它们组合在一起时,便天下无敌了。