工厂模式
function createPerson(name,age,job){ var o=new Object(); o.name=name; o.age=age; o.job=job; o.sayName=function(){ alert(this.name); }; return o; } var person1=createPerson('Bob',18,'student');
这种创建对象的方法虽然直观、简便,但是它有几点不好的地方:
- 用这种方法创建出来的对象,不能使用instanceof操作符去判断它是否是某个类(因为你都没有定义过任何一个类,你判断啥呀?),因为它只有
person1 instanceof Object
返回true
- 看到例子中的
o.sayName=function(){alert(this.name);};
,在每次创建对象的时候,都会创建一个function(){alert(this.name);}
然后将它赋给该对象的sayName
属性。而理想情况是:由于所有的对象的sayName
方法都是一样的,它们应该共用同一个方法,从而节省内存空间。
- 用这种方法创建出来的对象,不能使用instanceof操作符去判断它是否是某个类(因为你都没有定义过任何一个类,你判断啥呀?),因为它只有
构造函数模式
function Person(name,age,job){ this.name=name; this.age=age; this.job=job; this.sayName=function(){ alert(this.name); } } var person2=new Person('Lily',30,'teacher');
这种创建对象的方法更加直观了吧。这种方法和之前那个工厂模式比起来有一个优点。就是这种方法创建的对象能够使用
instanceof
操作符来判断该对象是不是某一个类。
console.log(person2 instanceof Person);//true
console.log(person2 instanceof Object);//true
但是它还是存在之前工厂模式的另一个问题:需要重复声明对象的方法,浪费内存。原型与构造函数结合
function Animal(name,color){ this.name=name; this.color=color; } Animal.prototype.sayName=function(){ console.log(this.name); } var animal1=new Animal('cat','white'); var animal2=new Animal('dog','black');
像这样,我们把所有对象共享的属性或者方法都添加到你所定义的这个类的原型对象中,就把上边所说的浪费内存的问题给解决了!
先别急着激动,这种方式又带来另外一个问题:怎么定义一个类还要分成两部分啊!看着好不爽啊!!(逼死强迫症)
唉,那就接着往下看。动态原型模式
function Dog(name,color){ this.name=name; this.color=color; if(typeof this.getColor != 'function'){ Dog.prototype.getColor=function(){ return this.color; }; } } var dog1=new Dog('dog1','white'); var dog2=new Dog('dog2','black');
这种方式,在创建第一个对象时,把所有对象共享的属性和方法都添加到这个类的原型对象中,节省了内存。而且给原型对象添加属性、方法的代码也都放到了构造函数里边,满足了强迫症程序员们的要求。真是完美!
稳妥构造函数模式
function B(b,c,d){ var o = new Object(); o.getB=function(){ return b; }; o.setB=function(newB){ b=newB; }; return o; } var b1=B(1,2,3);
当你打算创建一个对象,里边要定义一些属性,你又不想让别人使用的时候随便就能看到、修改(说这么多不说是想说封装嘛!!)的时候,可以使用这种方式。下面简单说一下这个方法的原理(不感兴趣的同学就可以至此为止了)。 在B函数中创建
function(){return b}
和function(newB){b=newB}
的时候,它们各自都有一条作用域链(默认同学们都知道作用域链了),在没有调用它们的时候,链的前端是B函数的执行环境对应的变量对象(好绕口),因为B函数中的o对象被作为返回值赋给了b1,所以这个对象在B函数执行完后不会销毁。重点来了:b1.setB和b1.getB所指向的2个函数的作用域链的前端,都指向了B函数,所以,B函数在执行完后,其中的变量(b,c,d,o)都没有销毁!所以调用b1.setB()可以修改b的值,也能返回b的值。结束!