有了第一篇的一些对对象的了解,后面学习如果来定义一个类也可以说成定义一个对象就会容易许多,废话就这么多了,继续开始学习。首先从定义对象的方式介绍。
1、工厂方式
当要定义一个名为“人”的类时,可以简单的设想我们需要为这个人设置属性:名字还有性别。可以简单地用一下代码实现:
var oPerson = new Object;
oPerson.name = "yzl";
oPerson.sex = "female";
oPerson.sayInfo = function(){
alert("name : " + this.name + " ,sex :" + this.sex);
};
这只是创建了一个简单的对象,那么如果要创建多个对象,现在就不满足了,所以引入了
工厂函数,进行改装之后的代码:
function createPerson(){
var oPerson = new Object;
oPerson.name = "yzl";
oPerson.sex = "female";
oPerson.sayInfo = function(){
alert(" name : " + this.name + " ,sex :" + this.sex);
};
return oPerson;
};
var p1 = createPerson();
p1.sayInfo();
p1.name = "gcm";
p1.sex = "female";
p1.sayInfo();
到这里看起来好像真的创建了一个人了,但是很明显能够看到不足,所有的实例的属性必须在对象创建了之后进行具体的修改,不能在对象建立时就根据具体情况创建对象。于是我们对代码进行了相关的修改,具体如下:
function createPerson(sName,sSex){
var oPerson = new Object;
oPerson.name = sName;
oPerson.sex = sSex;
oPerson.sayInfo = function(){
alert("name : " + this.name + " ,sex :" + this.sex);
};
return oPerson;
};
var p1 = createPerson("yzl","male");
var p2 = createPerson("gcm","female");
p1.sayInfo();
p2.sayInfo();
代码修改到这里基本上已经满足了需求,能够根据具体的情况创建不同的人。可是。。。(写到这里我突然感觉如此多的转折怎么跟春晚的魔术的托一样,大家原谅啊~),可是考虑一下内存,我们应该能够看到每次createPerson都会创建一个sayInfon()函数,即每个person都拥有自己对应的sayInfo方法,但是方法的内容都是相同的,所以应该选择更好的方式。考虑到EMCAScript是支持闭包的,所以可以将函数的定义放到类之外,让后让类的属性指向该方法的引用:
function sayInfo(){
alert("name : " + this.name + " ,sex :" + this.sex);
}
function createPerson(sName,sSex){
var oPerson = new Object;
oPerson.name = sName;
oPerson.sex = sSex;
oPerson.sayInfo = sayInfo;
return oPerson;
};
var p1 = createPerson("yzl","male");
var p2 = createPerson("gcm","female");
p1.sayInfo();
p2.sayInfo();
工厂模式已经满足了需求,从不断地修改代码的过程可以看出工厂模式存在的各种问题,于是便有了更加接近java代码的构造函数方式。
2、构造函数方式
构造函数方式和工厂模式非常的相似,只是在定义类的时候直接使用了类名,而参数的赋值使用了关键字
this,也不需要返回值。直接看代码:
function sayInfo(){
alert("name : " + this.name + " ,sex :" + this.sex);
}
function Person(sName,sSex){
this.name = sName;
this.sex = sSex;
this.sayInfo = sayInfo;
}
var p1 = new Person("yzl","male");
p1.sayInfo();
这种方式其实很像工厂模式,没有多少说的东西,继续下一种定义类的方式。
3、原型方式
该方式利用了对象的
prototype属性,可以把它看成新对象所依赖的原型。采用这种方式来定义一个类的方法一般是
先采用空的构造函数来设置类名,然后所有的属性和方法都被直接赋予prototype属性。参照以下代码:
function Person(){
}
Person.prototype.name = "yzl";
Person.prototype.sex = "male";
Person.prototype.sayInfo = function(){
alert("name : " + this.name + " ,sex :" + this.sex);
};
var p1 = new Person();
p1.sayInfo();
p1.name = "gcm";
p1.sex = "female";
p1.sayInfo();
采用原型方式创建实例时,原型的所有属性都被立即赋予要创建的对象,所有属性看起来都属于同一个对象,其中的sayInfo方法都指向同一个引用。使用该方法定义类可以使用instranceof运算符检查实例指向的类型。
alert(p1 instanceof Person); //true
采用原型方式存在了一个前面提到的劣势,某个实例的属性要等对象创建了之后才能根据具体的情况进行修改,这都是可以接受的。可是由于所有属性同时指向同一个引用,存在一个严重的问题,见代码:
function Person(){
}
Person.prototype.name = "yzl";
Person.prototype.sex = "male";
Person.prototype.friends = new Array("ymj","gcm");
Person.prototype.sayInfo = function(){
alert("name : " + this.name + " ,sex :" + this.sex);
};
var p1 = new Person();
var p2 = new Person();
p1.friends.push("hl");
alert(p2.friends); // ymj gcm hl
代码中明明只修改了p1的friends属性,可是p2的friends属性也产生了变化,这是一个非常严重的错误。个人感觉就跟这种方式是线程不安全的,多个线程访问就会出错。经过这么多的修改,于是提出了更加合理的方式:
联合使用构造函数和原型方式。
4、联合使用构造函数和原型方式
这种方式其实非常简单,基本的思路就是
采用构造函数来定义类的属性,采用原型方式来声明类的方法。这样就可以实现所有的对象独立占有自己的属性,而且保证了所有的方法只创建一次,代码如下:
function Person(sName,sSex){
this.name = sName;
this.sex = sSex;
this.friends = new Array();
}
Person.prototype.makeFriend = function(newFriend){
this.friends.push(newFriend);
}
Person.prototype.sayInfo = function(){
alert("name : " + this.name + " ,sex :" + this.sex + ", and has friends :" + this.friends );
};
var p1 = new Person("yzl","male");
var p2 = new Person("gcm","female");
p1.makeFriend("zxt");
p2.makeFriend("gr");
p1.sayInfo();
p2.sayInfo();
上面的这种方式已经很像java中创建一个对象了,这也是ECMAScript主要采用的方式。虽然还有其他几种创建类的方式,但是感觉记住最有用就可以了,其他的方式不再继续介绍,最后补充一种实现javascript重载的方法。首先必须先先了解一下Javascript中一个很重要的属性
arguments,它可以记录下在调用函数时所传递的参数,也就是通过它来实现函数的重载,代码如下:(由于最近忙于换工作所以写的比较慢请大家原谅)
function Person(sName,sSex){
switch(arguments.length){
case 0 :
this.name = "unKnown";
this.sex = "unKnown";
break;
case 1 :
this.name = sName;
this.sex = "unKnown";
break;
case 2 :
this.name = sName;
this.sex = sSex;
break;
};
}
Person.prototype.sayInfo = function(){
alert("name : " + this.name + " ,sex :" + this.sex);
};
var p1 = new Person("yzl","male");
var p2 = new Person("gcm");
var p3 = new Person();
p1.sayInfo();
p2.sayInfo();
p3.sayInfo();