Javascript 从名字上听起来跟JAVA有着联系,但其实却是两门根本不同的语言。在Java中定义类是轻而易举的事情,但是要在JavaScript中定义一个好的对象却是要花点心思。本文介绍几种方法,并比较他们的优劣。
1、 工厂方式
这种方式可能是我们最容易想到的了,见代码:
var employee = new Object;
employee.name = "Tim";
employee.age = 24;
employee.getName = function(){
alert(this.name);
}
这段代码创建了一个employee 对象,并设置了他的几个属性:name ,age 。而getName这个属性其实是一个指针,他指向一个函数,因而成为该对象的一个方法。使用这种方式可以创建一个对象,但是如果我们需要创建多个对象呢?总不能类似的再敲几片吧。我们把他封装一下,写出一个方法:
function createEmployee(names,ages){
var employee = new Object;
employee.name = names;
employee.age = ages;
employee.getName = function(){
alert(this.name);
}
return employee;
}
var employee1 = createEmployee("Tim",24);
var employee2 = createEmployee("Tom",22);
employee1.getName();
employee2.getName();
但是你会发现其实我们在创建两个对象的时候,创建了两个getName()方法,其实每个对象共享一个getName()就可以了,浪费内存空间。
2、构造函数方式
function Employee( names,ages ){
this.name = names;
this.age = ages;
this.getName= function(){
alert(this.name);
}
}
var employee1 = new Employee("Tim",24);
var employee2 = new Employee("Tom",22);
employee1.getName();
employee2.getName();
这种方式不像第一种方式需要在函数内部创建对象,而是使用了this关键字。然后用new来创建对象,这跟Java的非常相像了。但是他同样跟工厂模式一样会重复生成函数。
3、原型方式
function employee(){
}
employee.prototype.name = "Tim";
employee.prototype.age = 24;
employee.prototype.getName = function (){
alert( this.name );
};
var employee1 = new employee();
var employee2 = new employee();
使用这种方式很好的解决了前两种方法的问题,但是新的问题有来了,如果这样:
function employee(){
}
employee.prototype.name = "Tim";
employee.prototype.age = 24;
employee.prototype.friends = new Array( "Jack", "Tom" );
employee.prototype.getName = function (){
alert( this.name );
};
var employee1 = new employee();
var employee2 = new employee();
employee1.friends.push( "Tina" );
alert(employee1.friends);
alert(employee2.friends);
这两个对象都是输出“Jack,Tom,Tina”。这是因为friends是指向Array对象的指针,两个对象都指向同一个Array,因而修改一个对象的friends,另一个对象也是修改。这肯定不是我们想要的。
4、混合构造函数/原型模式
function Employee( names,ages ){
this.name = names;
this.age = ages;
this.friends = new Array( "Jack", "Tom" );
}
Employee.prototype.getName = function (){
alert( this.name );
};
var employee1 = new Employee("Tim",24);
var employee2 = new Employee("Tom",22);
employee1.friends.push( "Tina" );
alert(employee1.friends); //输出“Jack,Tom,Tina”
alert(employee2.friends); //输出“Jack,Tom”
结合构造和原型两种方式,彻底解决了上诉两种情况。他只创建一个getName实例,不会浪费内存,而且在修改friends属性时,也不会修改其他对象的friends属性。
5、动态原型方法
function Employee( names,ages ){
this.name = names;
this.age = ages;
this.friends = new Array( "Jack", "Tom" );
if( typeof Employee._initialized == "undefined" ){
Employee.prototype.getName = function(){
alert( this.name );
}
Employee._initialized = true;
}
}
使用这种方式,是不是觉得更像Java的CLASS编写方式了?
总结:通过比较,明显可以看出“构造函数/原型模式”和“动态原型”的优势,建议编程时采用。